/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#define USING_LOG_PREFIX SQL_RESV
#include "lib/compress/ob_compressor_pool.h"
#include "sql/resolver/ddl/ob_ddl_resolver.h"
#include "common/sql_mode/ob_sql_mode_utils.h"
#include "common/ob_store_format.h"
#include "lib/charset/ob_charset.h"
#include "lib/string/ob_sql_string.h"
#include "share/schema/ob_table_schema.h"
#include "share/schema/ob_part_mgr_util.h"
#include "sql/resolver/ddl/ob_create_table_stmt.h"
#include "sql/resolver/ddl/ob_alter_table_stmt.h"
#include "sql/resolver/ddl/ob_create_tablegroup_stmt.h"
#include "sql/code_generator/ob_expr_generator_impl.h"
#include "sql/code_generator/ob_code_generator_impl.h"
#include "sql/session/ob_sql_session_info.h"
#include "sql/ob_sql_utils.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/resolver/expr/ob_raw_expr_resolver_impl.h"
#include "sql/resolver/ob_resolver_utils.h"
#include "sql/resolver/expr/ob_raw_expr_printer.h"
#include "sql/resolver/expr/ob_raw_expr_part_func_checker.h"
#include "share/ob_index_builder_util.h"
#include "share/object/ob_obj_cast.h"
#include "observer/omt/ob_tenant_config_mgr.h"
namespace oceanbase {
using namespace common;
using namespace share::schema;
using namespace share;
using namespace obrpc;
namespace sql {

ObDDLResolver::ObDDLResolver(ObResolverParams& params)
    : ObStmtResolver(params),
      block_size_(OB_DEFAULT_SSTABLE_BLOCK_SIZE),
      consistency_level_(INVALID_CONSISTENCY),
      index_scope_(NOT_SPECIFIED),
      replica_num_(0),
      tablet_size_(-1),
      pctfree_(OB_DEFAULT_PCTFREE),
      tablegroup_id_(OB_INVALID_ID),
      index_attributes_set_(OB_DEFAULT_INDEX_ATTRIBUTES_SET),
      charset_type_(CHARSET_INVALID),
      collation_type_(CS_TYPE_INVALID),
      use_bloom_filter_(false),
      expire_info_(),
      compress_method_(),
      comment_(),
      tablegroup_name_(),
      primary_zone_(),
      row_store_type_(MAX_ROW_STORE),
      store_format_(OB_STORE_FORMAT_INVALID),
      progressive_merge_num_(OB_DEFAULT_PROGRESSIVE_MERGE_NUM),
      storage_format_version_(OB_STORAGE_FORMAT_VERSION_INVALID),
      table_id_(OB_INVALID_ID),
      data_table_id_(OB_INVALID_ID),
      index_table_id_(OB_INVALID_ID),
      virtual_column_id_(OB_INVALID_ID),
      read_only_(false),
      with_rowid_(false),
      table_name_(),
      database_name_(),
      partition_func_type_(PARTITION_FUNC_TYPE_HASH),
      auto_increment_(1),
      index_name_(),
      index_keyname_(NORMAL_KEY),
      global_(true),
      store_column_names_(),
      hidden_store_column_names_(),
      zone_list_(),
      sort_column_array_(),
      storing_column_set_(),
      has_index_using_type_(false),
      index_using_type_(share::schema::USING_BTREE),
      locality_(),
      is_random_primary_zone_(false),
      max_used_part_id_(OB_INVALID_ID),
      duplicate_scope_(share::ObDuplicateScope::DUPLICATE_SCOPE_NONE),
      enable_row_movement_(false),
      table_dop_(DEFAULT_TABLE_DOP),
      hash_subpart_num_(-1)
{
  table_mode_.reset();
}

ObDDLResolver::~ObDDLResolver()
{}

int ObDDLResolver::get_part_str_with_type(ObPartitionFuncType part_func_type, ObString& func_str, ObSqlString& part_str)
{
  int ret = OB_SUCCESS;
  ObString type_str;
  if (OB_FAIL(get_part_type_str(part_func_type, type_str))) {
    LOG_WARN("Failed to get part type str", K(ret));
  } else if (OB_FAIL(part_str.append_fmt(
                 "%.*s (%.*s)", type_str.length(), type_str.ptr(), func_str.length(), func_str.ptr()))) {
    LOG_WARN("Failed to append part str", K(ret));
  } else {
  }  // do nothing
  return ret;
}

/**
 * set default value for primary key
 */
int ObDDLResolver::get_primary_key_default_value(const ObObjType type, ObObj& default_value)
{
  int ret = OB_SUCCESS;
  switch (type) {
    case ObTinyIntType:
    case ObSmallIntType:
    case ObMediumIntType:
    case ObInt32Type:
    case ObIntType:
    case ObUTinyIntType:
    case ObUSmallIntType:
    case ObUMediumIntType:
    case ObUInt32Type:
    case ObUInt64Type:
      default_value.set_int(type, 0);
      break;
    case ObFloatType:
    case ObUFloatType:
      default_value.set_float(0);
      break;
    case ObDoubleType:
    case ObUDoubleType:
      default_value.set_double(0);
      break;
    case ObNumberType:  // set as string
    case ObUNumberType:
    case ObNumberFloatType:
      default_value.set_varchar("0");
      default_value.set_type(ObVarcharType);
      break;
    case ObYearType:
      default_value.set_year(ObTimeConverter::ZERO_YEAR);
      break;
    case ObDateType:
      default_value.set_date(ObTimeConverter::ZERO_DATE);
      break;
    case ObTimeType:
      default_value.set_time(ObTimeConverter::ZERO_TIME);
      break;
    case ObDateTimeType:
      default_value.set_datetime(ObTimeConverter::ZERO_DATETIME);
      break;
    case ObTimestampTZType:
    case ObTimestampLTZType:
    case ObTimestampNanoType:
      default_value.set_otimestamp_value(type, ObOTimestampData());
      break;
    case ObTimestampType:
      default_value.set_ext(ObActionFlag::OP_DEFAULT_NOW_FLAG);
      break;
    case ObCharType:
    case ObVarcharType:
    case ObNVarchar2Type:
    case ObNCharType:
      default_value.set_string(type, ObString("").ptr(), 0);
      break;
    case ObRawType:
      default_value.set_raw(ObString("").ptr(), 0);
      break;
    case ObIntervalYMType:
      default_value.set_interval_ym(ObIntervalYMValue());
      break;
    case ObIntervalDSType:
      default_value.set_interval_ds(ObIntervalDSValue());
      break;
    default:
      ret = OB_ERR_ILLEGAL_TYPE;
      SQL_RESV_LOG(WARN, "invalid  type of default value", K(type), K(ret));
      break;
  }
  return ret;
}

int update_datetime_default_value(
    ObObjParam& default_value, ParseNode& def_val, const ObObjType datetime_type, const int64_t action_flag)
{
  int ret = OB_SUCCESS;
  int16_t scale = 0;
  default_value.set_ext(action_flag);
  default_value.set_param_meta();
  if (def_val.value_ < 0) {
    scale = ObAccuracy::DDL_DEFAULT_ACCURACY[datetime_type].get_scale();
    default_value.set_scale(scale);
  } else if (OB_ISNULL(def_val.children_) || OB_UNLIKELY(1 != def_val.num_child_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(def_val.children_), K(def_val.num_child_));
  } else {
    if (NULL != def_val.children_[0]) {
      scale = static_cast<int16_t>(def_val.children_[0]->value_);
    } else if (lib::is_oracle_mode()) {
      scale = ObAccuracy::DDL_DEFAULT_ACCURACY[datetime_type].get_scale();
    } else {
      scale = 0;
    }
    default_value.set_scale(scale);
  }
  return ret;
}

int ObDDLResolver::resolve_default_value(ParseNode* def_node,
    //  const ObObjType column_data_type,
    ObObjParam& default_value)
{
  int ret = OB_SUCCESS;
  ObString tmp_str;
  ObString str;
  ObObj val;
  int16_t scale = -1;
  ObIAllocator* name_pool = NULL;
  ParseNode* def_val = NULL;
  if (NULL != def_node) {
    def_val = def_node;
    if (def_node->type_ == T_CONSTR_DEFAULT || (def_node->type_ == T_CONSTR_ORIG_DEFAULT)) {
      def_val = def_node->children_[0];
    }
    if (OB_ISNULL(allocator_) || OB_ISNULL(def_val)) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "allocator_ or def_val is null", K(allocator_), K(ret));
    } else {
      name_pool = static_cast<ObIAllocator*>(allocator_);
      if (OB_ISNULL(name_pool)) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "name pool is null", K(name_pool), K(ret));
      }
    }
    if (OB_FAIL(ret)) {
      // do nothing;
    } else {
      switch (def_val->type_) {
        case T_INT:
          default_value.set_int(def_val->value_);
          default_value.set_param_meta();
          break;
        case T_UINT64:
          default_value.set_uint64(static_cast<uint64_t>(def_val->value_));
          default_value.set_param_meta();
          break;
        case T_CHAR:
        case T_VARCHAR:
        case T_LOB:
          tmp_str.assign_ptr(const_cast<char*>(def_val->str_value_), static_cast<int32_t>(def_val->str_len_));
          if ((OB_FAIL(ob_write_string(*name_pool, tmp_str, str)))) {
            SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
            break;
          }
          default_value.set_varchar(str);
          default_value.set_collation_type(session_info_->get_local_collation_connection());
          default_value.set_param_meta();
          break;
        case T_RAW:
          tmp_str.assign_ptr(const_cast<char*>(def_val->str_value_), static_cast<int32_t>(def_val->str_len_));
          if ((OB_FAIL(ob_write_string(*name_pool, tmp_str, str)))) {
            SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
            break;
          }
          default_value.set_raw(str);
          default_value.set_param_meta();
          break;
        case T_HEX_STRING:
          tmp_str.assign_ptr(const_cast<char*>(def_val->str_value_), static_cast<int32_t>(def_val->str_len_));
          if ((OB_FAIL(ob_write_string(*name_pool, tmp_str, str)))) {
            SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
            break;
          }
          default_value.set_hex_string(str);
          default_value.set_scale(0);
          default_value.set_param_meta();
          break;
        case T_YEAR:
          default_value.set_year(static_cast<uint8_t>(def_val->value_));
          default_value.set_scale(0);
          default_value.set_param_meta();
          break;
        /*
         * mysql5.6 supports syntax like: c1 date|time|timestamp default date|time|timestamp'xxx'
         */
        case T_DATE: {
          ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
          int32_t time_val = 0;
          if (OB_FAIL(ObTimeConverter::str_to_date(time_str, time_val))) {
            ret = OB_ERR_WRONG_VALUE;
            LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "DATE", to_cstring(time_str));
          } else {
            default_value.set_date(time_val);
            default_value.set_scale(0);
            default_value.set_param_meta();
          }
          break;
        }
        case T_TIME: {
          ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
          int64_t time_val = 0;
          if (OB_FAIL(ObTimeConverter::str_to_time(time_str, time_val, &scale))) {
            ret = OB_ERR_WRONG_VALUE;
            LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "TIME", to_cstring(time_str));
          } else {
            default_value.set_time(time_val);
            default_value.set_scale(scale);
            default_value.set_param_meta();
          }
          break;
        }
        case T_TIMESTAMP: {
          ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
          int64_t time_val = 0;
          ObTimeConvertCtx cvrt_ctx(TZ_INFO(session_info_), false);
          if (OB_FAIL(ObTimeConverter::str_to_datetime(time_str, cvrt_ctx, time_val, &scale))) {
            ret = OB_ERR_WRONG_VALUE;
            LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "TIMESTAMP", to_cstring(time_str));
          } else {
            default_value.set_datetime(time_val);
            default_value.set_scale(scale);
            default_value.set_param_meta();
          }
          break;
        }
        case T_TIMESTAMP_TZ: {
          ObObjType value_type = ObMaxType;
          ObOTimestampData tz_value;
          ObTimeConvertCtx cvrt_ctx(TZ_INFO(session_info_), false);
          ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
          // if (OB_FAIL(ObTimeConverter::str_to_otimestamp(time_str, cvrt_ctx, tmp_type, ot_data))) {
          if (OB_FAIL(ObTimeConverter::literal_timestamp_validate_oracle(time_str, cvrt_ctx, value_type, tz_value))) {
            ret = OB_INVALID_DATE_VALUE;
            LOG_USER_ERROR(OB_INVALID_DATE_VALUE, "TIMESTAMP", to_cstring(time_str));
          } else {
            /* use max scale bug:#18093350 */
            default_value.set_otimestamp_value(value_type, tz_value);
            default_value.set_scale(OB_MAX_TIMESTAMP_TZ_PRECISION);
            default_value.set_param_meta();
          }
          break;
        }
        case T_DATETIME: {
          ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
          int64_t time_val = 0;
          ObTimeConvertCtx cvrt_ctx(TZ_INFO(session_info_), false);
          if (OB_FAIL(ObTimeConverter::literal_date_validate_oracle(time_str, cvrt_ctx, time_val))) {
            ret = OB_ERR_WRONG_VALUE;
            LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "DATE", to_cstring(time_str));
          } else {
            default_value.set_datetime(time_val);
            default_value.set_scale(OB_MAX_DATE_PRECISION);
            default_value.set_param_meta();
          }
          break;
        }
        case T_FLOAT: {
          int err = 0;
          double value = 0;
          char* endptr = NULL;
          value = ObCharset::strntod(def_val->str_value_, static_cast<int32_t>(def_val->str_len_), &endptr, &err);
          if (EOVERFLOW == err) {
            ret = OB_DATA_OUT_OF_RANGE;
          } else {
            default_value.set_float(static_cast<float>(value));
            default_value.set_param_meta();
          }
          break;
        }
        case T_DOUBLE: {
          int err = 0;
          double value = 0;
          char* endptr = NULL;
          value = ObCharset::strntod(def_val->str_value_, static_cast<int32_t>(def_val->str_len_), &endptr, &err);
          if (EOVERFLOW == err) {
            ret = OB_DATA_OUT_OF_RANGE;
          } else {
            default_value.set_double(value);
            default_value.set_param_meta();
          }
          break;
        }
        case T_NUMBER:
        case T_NUMBER_FLOAT: {  // set as string
          ObString number(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
          if (OB_FAIL(ob_write_string(*name_pool, number, str))) {
            SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
            break;
          }
          default_value.set_varchar(str);
          default_value.set_type(ObVarcharType);
          default_value.set_collation_type(ObCharset::get_system_collation());
          default_value.set_param_meta();
          break;
        }
        case T_BOOL:
          default_value.set_bool(def_val->value_ == 1 ? true : false);
          default_value.set_param_meta();
          break;
        case T_NULL:
          default_value.set_type(ObNullType);
          default_value.set_param_meta();
          break;
        case T_FUN_SYS_CUR_TIMESTAMP: {
          ret = update_datetime_default_value(
              default_value, *def_val, ObTimestampType, ObActionFlag::OP_DEFAULT_NOW_FLAG);
          break;
        }
        case T_OP_POS:
          ret = resolve_default_value(def_val->children_[0], default_value);
          break;
        case T_OP_NEG: {
          ObObjParam old_obj;
          ret = resolve_default_value(def_val->children_[0], old_obj);
          if (OB_FAIL(ret)) {
            SQL_RESV_LOG(WARN, "Resolve default const value failed", K(ret));
          } else if (ObIntType == old_obj.get_type()) {
            int64_t value = 0;
            old_obj.get_int(value);
            default_value.set_int(-value);
            default_value.set_param_meta();
          } else if (ObFloatType == old_obj.get_type()) {
            float value = 0.0f;
            old_obj.get_float(value);
            default_value.set_float(-value);
            default_value.set_param_meta();
          } else if (ObDoubleType == old_obj.get_type()) {
            double value = 0.0;
            if (OB_FAIL(old_obj.get_double(value))) {
              SQL_RESV_LOG(WARN, "failed to get double value", K(ret));
            } else {
              default_value.set_double(-value);
              default_value.set_param_meta();
            }
          } else if (T_NUMBER == def_val->children_[0]->type_) {
            ObString str;
            old_obj.get_varchar(str);
            char buffer[number::ObNumber::MAX_PRINTABLE_SIZE];
            snprintf(buffer, sizeof(buffer), "-%.*s", str.length(), str.ptr());
            if ((OB_FAIL(ob_write_string(*name_pool, ObString::make_string(buffer), str)))) {
              SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
              break;
            }
            default_value.set_varchar(str);
            default_value.set_collation_type(ObCharset::get_system_collation());
            default_value.set_param_meta();
          } else {
            ret = OB_ERR_PARSER_SYNTAX;
            SQL_RESV_LOG(WARN, "Invalid flag '-' in default value", K(ret));
          }
          break;
        }
        case T_INTERVAL_YM:
        case T_INTERVAL_DS:
        case T_NVARCHAR2:
        case T_NCHAR:
        case T_UROWID: {
          // oracle's default value is stored as string, won't be here
          ret = OB_NOT_SUPPORTED;
          break;
        }
        default:
          ret = OB_ERR_ILLEGAL_TYPE;
          SQL_RESV_LOG(WARN, "Illegal type of default value", K(ret), K(def_val->type_));
          break;
      }
    }
  } else {
    default_value.set_null();
    default_value.set_param_meta();
  }
  if (OB_SUCC(ret)) {
    _OB_LOG(DEBUG, "resolve default value: %s", to_cstring(default_value));
  }
  return ret;
}

int ObDDLResolver::set_table_name(const ObString& table_name)
{
  int ret = OB_SUCCESS;
  if (allocator_) {
    if (OB_FAIL(ob_write_string(*allocator_, table_name, table_name_))) {
      SQL_RESV_LOG(WARN, "deep copy table name failed", K(ret));
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "allocator is null", K(ret));
  }
  return ret;
}

int ObDDLResolver::set_database_name(const ObString& database_name)
{
  int ret = OB_SUCCESS;
  if (allocator_) {
    if (OB_FAIL(ob_write_string(*allocator_, database_name, database_name_))) {
      SQL_RESV_LOG(WARN, "deep copy table name failed", K(ret));
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "allocator is null", K(ret));
  }
  return ret;
}

int ObDDLResolver::resolve_table_options(ParseNode* node, bool is_index_option)
{
  int ret = OB_SUCCESS;
  if (NULL != node) {
    ParseNode* option_node = NULL;
    int32_t num = 0;
    if (T_TABLE_OPTION_LIST != node->type_ || node->num_child_ < 1) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "invalid parse node", K(ret));
    } else if (OB_ISNULL(node->children_) || OB_ISNULL(session_info_)) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "node children or session_info_ is null", K(node->children_), K(session_info_), K(ret));
    } else {
      num = node->num_child_;
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < num; ++i) {
      if (OB_ISNULL(option_node = node->children_[i])) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "node is null", K(ret));
      } else if (OB_FAIL(resolve_table_option(option_node, is_index_option))) {
        SQL_RESV_LOG(WARN, "resolve table option failed", K(ret));
      }
    }
  }
  if (OB_SUCC(ret)) {
    if (CHARSET_INVALID == charset_type_ && CS_TYPE_INVALID == collation_type_) {
      // The database character set and collation affect these aspects of server operation:
      //
      // For CREATE TABLE statements, the database character set and collation are used as default
      // values for table definitions if the table character set and collation are not specified.
      // To override this, provide explicit CHARACTER SET and COLLATE table options.
      int64_t coll_cs_db_int64 = -1;
      int64_t coll_db_int64 = -1;
      if (OB_FAIL(session_info_->get_sys_variable(share::SYS_VAR_CHARACTER_SET_DATABASE, coll_cs_db_int64))) {
        SQL_RESV_LOG(WARN, "fail to get sys variable character_set_database", K(ret));
      } else if (OB_FAIL(session_info_->get_sys_variable(share::SYS_VAR_COLLATION_DATABASE, coll_db_int64))) {
        SQL_RESV_LOG(WARN, "fail to get sys variable collation_database", K(ret));
      } else if (!ObCharset::is_valid_collation(coll_cs_db_int64) || !ObCharset::is_valid_collation(coll_db_int64)) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "invalid collation type", K(ret), K(coll_cs_db_int64), K(coll_db_int64));
      } else {
        charset_type_ = ObCharset::charset_type_by_coll(static_cast<ObCollationType>(coll_cs_db_int64));
        collation_type_ = static_cast<ObCollationType>(coll_db_int64);
      }
    } else if (OB_FAIL(ObCharset::check_and_fill_info(charset_type_, collation_type_))) {
      SQL_RESV_LOG(WARN, "fail to fill collation info", K(ret));
    }
  }
  return ret;
}

/**
 * @param check_column_exist is used for 'alter table add index'/'create index' to ignore schema check
 * check_column_exist default is true
 */
int ObDDLResolver::add_storing_column(const ObString& column_name, bool check_column_exist, bool is_hidden)
{
  int ret = OB_SUCCESS;
  ObString col_name;
  if (OB_ISNULL(schema_checker_) || OB_ISNULL(stmt_) || OB_ISNULL(session_info_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "schema checker or stmt cat not be null", K(ret));
  }
  if (OB_SUCCESS == ret && check_column_exist) {
    ObColumnSchemaV2* column_schema = NULL;

    if (stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
      ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
      ObTableSchema& tbl_schema = create_table_stmt->get_create_table_arg().schema_;
      if (NULL == (column_schema = tbl_schema.get_column_schema(column_name))) {
        ret = OB_ERR_BAD_FIELD_ERROR;
        LOG_USER_ERROR(
            OB_ERR_BAD_FIELD_ERROR, column_name.length(), column_name.ptr(), table_name_.length(), table_name_.ptr());
      } else if (ob_is_text_tc(column_schema->get_data_type())) {
        ret = OB_ERR_WRONG_KEY_COLUMN;
        LOG_USER_ERROR(OB_ERR_WRONG_KEY_COLUMN, column_name.length(), column_name.ptr());
      } else if (ObTimestampTZType == column_schema->get_data_type()) {
        ret = OB_ERR_WRONG_KEY_COLUMN;
        LOG_USER_ERROR(OB_ERR_WRONG_KEY_COLUMN, column_name.length(), column_name.ptr());
      }
    }
    if (OB_SUCC(ret)) {
      if (OB_ISNULL(column_schema)) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "column schema is null", K(ret));
      } else if (column_schema->get_rowkey_position() > 0) {
        // rowkey can't be used as storing column, so ignore it
      } else {
        // do nothing;
      }
    }
  }
  if (OB_SUCC(ret)) {
    ObColumnNameHashWrapper column_name_key(column_name);
    ObColumnNameWrapper column_key(column_name, 0);  // prefix length of storing column is 0
    bool check_prefix_len = true;
    if (is_column_exists(sort_column_array_, column_key, check_prefix_len)) {
      // column exists in sort columns, so ignore it
    } else if (OB_HASH_EXIST == storing_column_set_.exist_refactored(column_name_key)) {
      if (is_hidden) {
        // try add storing column by observer, and column is duplicate, just ignore
      } else {
        ret = OB_ERR_COLUMN_DUPLICATE;
        LOG_USER_ERROR(OB_ERR_COLUMN_DUPLICATE, column_name.length(), column_name.ptr());
      }
    } else if (OB_FAIL(storing_column_set_.set_refactored(column_name_key))) {
      SQL_RESV_LOG(WARN, "set column name to storing column set failed", K(ret));
    } else if (!is_hidden && OB_FAIL(store_column_names_.push_back(column_name))) {
      SQL_RESV_LOG(WARN, "add column name failed", K(column_name), K(ret));
    } else if (is_hidden && OB_FAIL(hidden_store_column_names_.push_back(column_name))) {
      SQL_RESV_LOG(WARN, "add column name failed", K(column_name), K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::add_fulltext_column(const ObString& column_name)
{
  int ret = OB_SUCCESS;
  ObColumnNameHashWrapper key_name(column_name);
  ObColumnNameWrapper key_column_name(column_name, 0);
  bool check_prefix_len = false;
  if (!is_column_exists(sort_column_array_, key_column_name, check_prefix_len)) {
    ret = OB_ERR_KEY_COLUMN_DOES_NOT_EXITS;
    LOG_USER_ERROR(OB_ERR_KEY_COLUMN_DOES_NOT_EXITS, column_name.length(), column_name.ptr());
  } else if (OB_HASH_EXIST == (ret = fulltext_column_set_.exist_refactored(key_name))) {
    ret = OB_ERR_COLUMN_DUPLICATE;
    LOG_USER_ERROR(OB_ERR_COLUMN_DUPLICATE, column_name.length(), column_name.ptr());
  } else if (OB_HASH_NOT_EXIST != ret) {
    LOG_WARN("check column name whether in fulltext columns failed", K(ret), K(column_name));
  } else if (OB_FAIL(fulltext_column_set_.set_refactored(key_name))) {
    LOG_WARN("set column name to fulltext column set failed", K(ret), K(column_name));
  } else if (OB_FAIL(fulltext_column_names_.push_back(column_name))) {
    LOG_WARN("add column name to fulltext columns failed", K(ret), K(column_name));
  }
  return ret;
}

int ObDDLResolver::resolve_table_option(const ParseNode* option_node, const bool is_index_option)
{
  int ret = OB_SUCCESS;
  const uint64_t tenant_id = session_info_->get_effective_tenant_id();
  ObString database_name;
  uint64_t database_id = OB_INVALID_ID;
  if (OB_ISNULL(stmt_) || OB_ISNULL(allocator_) || OB_ISNULL(schema_checker_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "allocator_ or stmt_ or schema_checker_ cat not be null", K(ret));
  } else {
    database_name = database_name_;
  }
  CHECK_COMPATIBILITY_MODE(session_info_);
  if (OB_FAIL(ret)) {
    // do nothing
  } else if (OB_FAIL(schema_checker_->get_database_id(tenant_id, database_name, database_id))) {
    SQL_RESV_LOG(WARN, "fail to get database_id.", K(ret), K(database_name), K(tenant_id));
  }
  if (OB_SUCCESS == ret && NULL != option_node) {
    switch (option_node->type_) {
      case T_EXPIRE_INFO: {
        //        //not supported in version(1.0)
        //        ret = OB_NOT_SUPPORTED;
        //        LOG_USER_ERROR(ret, "expire info in version(1.0)");
        //        if (stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
        //          ret = OB_ERR_PARSE_SQL;
        //          SQL_RESV_LOG(WARN, "Expire info can not be specified in index option", K(ret));
        //        }
        //        const bool is_index_table = false;
        //        if (OB_ISNULL(option_node->children_)) {
        //          ret = OB_ERR_UNEXPECTED;
        //          SQL_RESV_LOG(WARN, "(the children of option_node is null", K(option_node->children_), K(ret));
        //        } else if (NULL != option_node->children_[0] && T_NULL == option_node->children_[0]->type_) {
        //          //drop expire info
        //          expire_info_.assign_ptr(NULL, 0);
        //        } else {
        //          ObRawExpr *expr = NULL;
        //          ObString expire_info;
        //          expire_info.assign_ptr(const_cast<char *>(option_node->str_value_),
        //                                 static_cast<int32_t>(option_node->str_len_));
        //          if (OB_ISNULL(option_node->children_[0])) {
        //            ret = OB_ERR_UNEXPECTED;
        //            SQL_RESV_LOG(ERROR,"children can't be null", K(ret));
        //          } else if (OB_FAIL(ob_write_string(*allocator_, expire_info, expire_info_))) {
        //            SQL_RESV_LOG(WARN, "write string failed", K(ret));
        //          } else {
        //            if (stmt::T_ALTER_TABLE != stmt_->get_stmt_type()) {
        //              if (OB_FAIL(schema_checker_->get_table_schema(tenant_id, database_id, table_name_,
        //                                                            is_index_table, &tab_schema))) {
        //                SQL_RESV_LOG(WARN, "table is not exist", K(tenant_id), K(database_id), K_(table_name),
        //                K(ret));
        //              } else if (OB_ISNULL(tab_schema)) {
        //                ret = OB_ERR_UNEXPECTED;
        //                SQL_RESV_LOG(WARN, "tab schema is null", K(tab_schema), K(ret));
        //              } else if ((tab_schema->get_progressive_merge_num() > 1 || progressive_merge_num_ > 1)
        //                         && tab_schema->get_index_tid_count() > 0) {
        //                ret = OB_OP_NOT_ALLOW;
        //                SQL_RESV_LOG(WARN, "this progressive merge num > 1 and contain index table", K(ret));
        //              } else if (OB_FAIL(resolve_sql_expr(*(option_node->children_[0]), expr, T_EXPIRE_SCOPE))
        //                  || OB_FAIL(stmt_->get_condition_exprs().push_back(expr))) {
        //                if (OB_ERR_BAD_FIELD_ERROR != ret) {
        //                  SQL_RESV_LOG(WARN, "Resolve expire info failed", K(ret));
        //                }
        //              }
        //            } else {
        //              //mark alter table option
        //              if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::EXPIRE_INFO))) {
        //                SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
        //              }
        //            }
        //          }
        //        }
        break;
      }
      case T_BLOCK_SIZE: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
        } else {
          const int64_t block_size = option_node->children_[0]->value_;
          if (block_size < MIN_BLOCK_SIZE || block_size > MAX_BLOCK_SIZE) {
            ret = OB_ERR_INVALID_BLOCK_SIZE;
            SQL_RESV_LOG(WARN, "block size should between 1024 and 1048576", K(block_size), K(ret));
          } else {
            block_size_ = block_size;
          }
        }
        if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::BLOCK_SIZE))) {
            SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
          }
        }
        break;
      }
      case T_REPLICA_NUM: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            replica_num_ = static_cast<int32_t>(option_node->children_[0]->value_);
            if (replica_num_ <= 0 || MAX_REPLICA_NUM < replica_num_) {
              ret = OB_NOT_SUPPORTED;
              SQL_RESV_LOG(WARN, "Invalid replica_num", K_(replica_num), K(ret));
            }
          }
          if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::REPLICA_NUM))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("index option should not specify replica num", K(ret));
        }
        break;
      }
      case T_TABLET_SIZE: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            tablet_size_ = option_node->children_[0]->value_;
            if (tablet_size_ < 0 || tablet_size_ & ((1 << 21) - 1)) {
              ret = OB_INVALID_CONFIG;
              SQL_RESV_LOG(WARN, "tablet_size must be a multiple of 2M", K_(tablet_size), K(ret));
            }
          }
          if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLET_SIZE))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("index option should not specify tablet size", K(ret));
        }
        break;
      }
      case T_PCTFREE: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
        } else {
          pctfree_ = static_cast<int32_t>(option_node->children_[0]->value_);
          if (pctfree_ < 0 || pctfree_ >= OB_MAX_PCTFREE) {
            if (share::is_oracle_mode()) {
              ret = OB_ERR_INVALID_PCTFREE_OR_PCTUSED_VALUE;
            } else {
              ret = OB_INVALID_CONFIG;
            }
            SQL_RESV_LOG(WARN, "invalid pctfree value", K(ret), K_(pctfree));
          }
        }
        if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::PCTFREE))) {
            SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
          }
        }
        break;
      }
      case T_PCTUSED: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
        } else {
          int64_t pctused = static_cast<int32_t>(option_node->children_[0]->value_);
          if (pctused <= 0 || pctused > OB_MAX_PCTUSED) {
            ret = OB_ERR_INVALID_PCTFREE_OR_PCTUSED_VALUE;
            SQL_RESV_LOG(WARN, "invalid pctused value", K(ret), K(pctused));
          }
        }
        break;
      }
      case T_INITRANS: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
        } else {
          int64_t initrans = static_cast<int32_t>(option_node->children_[0]->value_);
          if (initrans <= 0 || initrans > OB_MAX_TRANS) {
            ret = OB_ERR_INVALID_INITRANS_VALUE;
            SQL_RESV_LOG(WARN, "invalid initrans value", K(ret), K(initrans));
          }
        }
        break;
      }
      case T_MAXTRANS: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
        } else {
          int64_t maxtrans = static_cast<int32_t>(option_node->children_[0]->value_);
          if (maxtrans < 0 || maxtrans > OB_MAX_TRANS) {
            ret = OB_ERR_INVALID_MAXTRANS_VALUE;
            SQL_RESV_LOG(WARN, "invalid initrans value", K(ret), K(maxtrans));
          }
        }
        break;
      }
      case T_STORAGE_OPTIONS: {
        if (0 == option_node->num_child_) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node's num child can not be 0", K(ret), K(option_node->num_child_));
        }
        for (int64_t i = 0; OB_SUCC(ret) && i < option_node->num_child_; ++i) {
          if (OB_ISNULL(option_node->children_[i])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null!", K(ret), K(i));
          } else {
            // TODO: only support storage syntax
          }
        }
        break;
      }
      case T_COMPRESSION: {
        if (!is_index_option) {
          ObString tmp_str;
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            tmp_str.assign_ptr(const_cast<char*>(option_node->children_[0]->str_value_),
                static_cast<int32_t>(option_node->children_[0]->str_len_));
            compress_method_ = tmp_str.trim();
          }
          bool is_find = false;
          const char* find_compress_name = NULL;
          for (int i = 0; OB_SUCC(ret) && i < ARRAYSIZEOF(common::compress_funcs) && !is_find; i++) {
            if (0 == ObString::make_string(compress_funcs[i]).case_compare(compress_method_)) {
              is_find = true;
              find_compress_name = compress_funcs[i];
            }
          }
          if (OB_FAIL(ret)) {
            // do nothing
          } else if (OB_ISNULL(find_compress_name)) {
            ret = OB_INVALID_ARGUMENT;
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, to_cstring(compress_method_));
          } else if (OB_FAIL(ob_write_string(*allocator_, find_compress_name, compress_method_))) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "write string failed", K(ret));
          } else {
          }
          if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::COMPRESS_METHOD))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify compress method", K(ret));
        }
        break;
      }
      case T_STORE_FORMAT: {
        if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2100) {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("Create table with store format option not supported in old version", K(ret));
        } else if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            store_format_ = static_cast<ObStoreFormatType>(option_node->children_[0]->value_);
            if (!ObStoreFormat::is_store_format_valid(store_format_, share::is_oracle_mode())) {
              ret = OB_ERR_UNEXPECTED;
              SQL_RESV_LOG(WARN, "Unexpected invalid store format value", K_(store_format), K(ret));
            } else {
              row_store_type_ = ObStoreFormat::get_row_store_type(store_format_);
            }
            if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
              if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::STORE_FORMAT))) {
                SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
              } else if (share::is_oracle_mode()) {
                const char* compress_name = ObStoreFormat::get_store_format_compress_name(store_format_);
                if (OB_ISNULL(compress_name)) {
                  ret = OB_ERR_UNEXPECTED;
                  SQL_RESV_LOG(WARN, "Unexpected null compress_name", K_(store_format), K(ret));
                } else if (OB_FAIL(
                               ob_write_string(*allocator_, ObString::make_string(compress_name), compress_method_))) {
                  ret = OB_ERR_UNEXPECTED;
                  SQL_RESV_LOG(WARN, "write string failed", K(ret));
                } else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::COMPRESS_METHOD))) {
                  SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
                }
              }
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify compress format", K(ret));
        }
        break;
      }
      case T_PROGRESSIVE_MERGE_NUM: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            progressive_merge_num_ = option_node->children_[0]->value_;
          }
          if (OB_FAIL(ret)) {
            // do nothing
          } else if (progressive_merge_num_ < 0 || progressive_merge_num_ > MAX_PROGRESSIVE_MERGE_NUM) {
            ret = OB_INVALID_ARGUMENT;
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "progressive_merge_num");
          } else {
            if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
              if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::PROGRESSIVE_MERGE_NUM))) {
                SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
              }
            } else if (stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
              ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
              ObTableSchema& tbl_schema = create_table_stmt->get_create_table_arg().schema_;
              if (!tbl_schema.is_user_table()) {
                ret = OB_OP_NOT_ALLOW;
                SQL_RESV_LOG(WARN, "only allow to set progressive merge num for data table", K(ret));
              }
            } else {
              ret = OB_ERR_PARSE_SQL;
              SQL_RESV_LOG(WARN, "PROGRESSIVE_MERGE_NUM can not be specified in creating index", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify progressive merge num", K(ret));
        }
        break;
      }
      case T_STORAGE_FORMAT_VERSION: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            storage_format_version_ = option_node->children_[0]->value_;
          }
          if (OB_FAIL(ret)) {
            // do nothing
          } else if (storage_format_version_ < OB_STORAGE_FORMAT_VERSION_V1 ||
                     storage_format_version_ >= OB_STORAGE_FORMAT_VERSION_MAX) {
            ret = OB_INVALID_ARGUMENT;
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "invalid storage format version");
          } else {
            if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
              if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::STORAGE_FORMAT_VERSION))) {
                SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
              }
            } else if (stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
              ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
              ObTableSchema& tbl_schema = create_table_stmt->get_create_table_arg().schema_;
              if (!tbl_schema.is_user_table()) {
                ret = OB_OP_NOT_ALLOW;
                SQL_RESV_LOG(WARN, "only allow to set storage format version for data table", K(ret));
              }
            } else {
              ret = OB_ERR_PARSE_SQL;
              SQL_RESV_LOG(WARN, "STORAGE_FORMAT_VERSION can not be specified in creating index", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should be be specified storage_format_version", K(ret));
        }
        break;
      }
      case T_USE_BLOOM_FILTER: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            use_bloom_filter_ = option_node->children_[0]->value_ ? true : false;
          }
          if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::USE_BLOOM_FILTER))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify use bloom filter", K(ret));
        }
        break;
      }
      case T_INDEX_SCOPE: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
        } else {
          index_scope_ = option_node->children_[0]->value_ == 0 ? LOCAL_INDEX : GLOBAL_INDEX;
        }
        if (OB_SUCCESS == ret && GLOBAL_INDEX == index_scope_) {
          if (OB_ISNULL(option_node->children_[1])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[1]), K(ret));
          } else if (0 != STRNCMP("GLOBAL",
                              static_cast<const char*>(option_node->children_[1]->str_value_),
                              option_node->children_[1]->str_len_)) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(ERROR, "invalid index type!", K(ret));
          }
        }
        if (OB_SUCCESS == ret && LOCAL_INDEX == index_scope_) {
          if (OB_ISNULL(option_node->children_[1])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[1]), K(ret));
          } else if (0 != STRNCMP("LOCAL",
                              static_cast<const char*>(option_node->children_[1]->str_value_),
                              option_node->children_[1]->str_len_)) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(ERROR, "invalid index type!", K(ret));
          }
        }
        break;
      }
      case T_REVERSE: {
        // support dummy syntax only
        break;
      }
      case T_STORING_COLUMN_LIST: {
        ParseNode* cur_node = NULL;
        ObString column_name;
        if (OB_ISNULL(option_node->children_[0]) || T_STORING_COLUMN_LIST != option_node->type_ ||
            option_node->num_child_ < 1) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(ERROR, "invalid node type and node child!", K(ret));
        }
        for (int64_t i = 0; OB_SUCCESS == ret && i < option_node->num_child_; i++) {
          if (OB_ISNULL(option_node->children_[i])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "invalid node type and node child!", K(ret));
          } else {
            cur_node = option_node->children_[i];
            if (OB_ISNULL(cur_node)) {
              ret = OB_ERR_UNEXPECTED;
              SQL_RESV_LOG(ERROR, "invalid node type and node child!", K(cur_node), K(ret));
            } else {
              int32_t len = static_cast<int32_t>(cur_node->str_len_);
              column_name = ObString(len, len, cur_node->str_value_);
            }
          }
          if (OB_FAIL(ret)) {
          } else if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
            bool check_column_exist = false;
            if (OB_FAIL(add_storing_column(column_name, check_column_exist))) {
              SQL_RESV_LOG(WARN, "Add storing column failed", K(ret), K(column_name));
            }
          } else {
            if (OB_FAIL(add_storing_column(column_name))) {
              SQL_RESV_LOG(WARN, "Add storing column failed", K(ret), K(column_name));
            }
            if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
              if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLEGROUP_NAME))) {
                SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
              }
            }
          }
        }
        break;
      }
      case T_PARSER_NAME: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("option_node child is null");
        } else {
          int32_t str_len = static_cast<int32_t>(option_node->children_[0]->str_len_);
          parser_name_.assign_ptr(option_node->children_[0]->str_value_, str_len);
        }
        break;
      }
      case T_WITH_ROWID: {
        with_rowid_ = true;
        break;
      }
      case T_COMMENT: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
        } else {
          comment_ = ObString(option_node->children_[0]->str_len_, option_node->children_[0]->str_value_);
          ObCollationType client_cs_type = session_info_->get_local_collation_connection();
          if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
                  *allocator_, comment_, comment_, client_cs_type, CS_TYPE_UTF8MB4_BIN))) {
            LOG_WARN("fail to convert comment to utf8", K(ret));
          }
        }
        if (OB_SUCC(ret)) {
          if (comment_.length() > MAX_TABLE_COMMENT_LENGTH) {
            comment_ = "";
            if (is_index_option) {
              ret = OB_ERR_TOO_LONG_INDEX_COMMENT;
              LOG_USER_ERROR(OB_ERR_TOO_LONG_INDEX_COMMENT, MAX_INDEX_COMMENT_LENGTH);
            } else {
              ret = OB_ERR_TOO_LONG_TABLE_COMMENT;
              LOG_USER_ERROR(OB_ERR_TOO_LONG_TABLE_COMMENT, MAX_TABLE_COMMENT_LENGTH);
            }
          }
        }
        if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::COMMENT))) {
            SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
          }
        }
        break;
      }
      case T_TABLEGROUP: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            tablegroup_name_.assign_ptr((char*)(option_node->children_[0]->str_value_),
                static_cast<int32_t>(option_node->children_[0]->str_len_));
            tablegroup_id_ = OB_INVALID_ID;
          }
          if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLEGROUP_NAME))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify tablegrouop", K(ret));
        }
        break;
      }
      case T_TABLE_MODE: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
        } else {
          bool is_sync_ddl_user = false;
          ObString table_mode_str(static_cast<int32_t>(option_node->children_[0]->str_len_),
              (char*)(option_node->children_[0]->str_value_));
          if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
            LOG_WARN("Failed to check sync_ddl_user", K(ret));
          } else if (is_sync_ddl_user) {  // in backup mode
            if (OB_FAIL(ObBackUpTableModeOp::get_table_mode(table_mode_str, table_mode_))) {
              LOG_WARN("Failed to get table mode from string", K(ret), K(table_mode_str));
            }
          } else if (0 == table_mode_str.case_compare("normal")) {
            table_mode_.mode_flag_ = TABLE_MODE_NORMAL;
          } else {
            ret = OB_ERR_PARSER_SYNTAX;
          }
          if (OB_FAIL(ret)) {
            SQL_RESV_LOG(WARN, "failed to resolve table mode str!", K(ret));
          }
        }
        if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLE_MODE))) {
            SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
          } else {
            ObTableSchema tmp_table_schema;
            if (OB_FAIL(get_table_schema_for_check(tmp_table_schema))) {
              LOG_WARN("get table schema failed", K(ret));
            } else if (table_mode_.mode_flag_ != TABLE_MODE_NORMAL) {
              // alter table change PK_MODE not suppoted
              ret = OB_NOT_SUPPORTED;
              LOG_USER_ERROR(OB_NOT_SUPPORTED, "Unsupported table mode");
              SQL_RESV_LOG(WARN, "Unsupported table mode", K(ret), K(table_mode_));
            } else {
              table_mode_.pk_mode_ = tmp_table_schema.get_table_mode_struct().pk_mode_;
            }
          }
        }
        break;
      }
      case T_CHARSET: {
        if (!is_index_option) {
          if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            ret = OB_NOT_SUPPORTED;
            SQL_RESV_LOG(WARN, "Not support to alter charset", K(ret));
          } else if (CHARSET_INVALID == charset_type_) {
            if (OB_ISNULL(option_node->children_[0])) {
              ret = OB_ERR_UNEXPECTED;
              SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
            } else {
              ObString node_value(option_node->children_[0]->str_len_, option_node->children_[0]->str_value_);
              ObString charset = node_value.trim();
              ObCharsetType charset_type = ObCharset::charset_type(charset);
              if (CHARSET_INVALID == charset_type) {
                ret = OB_ERR_UNKNOWN_CHARSET;
                LOG_USER_ERROR(OB_ERR_UNKNOWN_CHARSET, charset.length(), charset.ptr());
              } else {
                charset_type_ = charset_type;
              }
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify charset");
        }
        break;
      }
      case T_COLLATION: {
        if (!is_index_option) {
          if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            ret = OB_ERR_PARSE_SQL;
            SQL_RESV_LOG(WARN, "Not support to alter collation", K(ret));
          } else if (CS_TYPE_INVALID == collation_type_) {
            ObString node_value(option_node->str_len_, option_node->str_value_);
            ObString collation = node_value.trim();
            ObCollationType collation_type = ObCharset::collation_type(collation);
            if (CS_TYPE_INVALID == collation_type) {
              ret = OB_ERR_UNKNOWN_COLLATION;
              LOG_USER_ERROR(OB_ERR_UNKNOWN_COLLATION, collation.length(), collation.ptr());
            } else {
              collation_type_ = collation_type;
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify collation", K(ret));
        }
        break;
      }
      case T_TABLE_ID: {
        if (!is_index_option) {
          if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            ret = OB_ERR_PARSE_SQL;
            SQL_RESV_LOG(WARN, "Not support to alter table id", K(ret));
            break;
          }
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            table_id_ = static_cast<uint64_t>(option_node->children_[0]->value_);
            if (is_cte_table(table_id_)) {
              ret = OB_INVALID_ARGUMENT;
              LOG_WARN("This table cann't be a cte table", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify table_id", K(ret));
        }
        break;
      }
      case T_DATA_TABLE_ID: {
        if (is_index_option && stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            uint64_t table_id = static_cast<uint64_t>(option_node->children_[0]->value_);
            // bool is_sync_ddl_user = false;
            // if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
            //  LOG_WARN("Failed to check check_sync_ddl_user", K(ret));
            // } else if (!is_sync_ddl_user) {
            //   ret = OB_ERR_PARSE_SQL;
            //  LOG_WARN("Only support for sync ddl user to specify data_table_id", K(ret),
            //  K(session_info_->get_user_name()));
            // } else {
            data_table_id_ = table_id;
            // }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("only create index can specify data_table_id for restore purpose", K(ret));
        }
        break;
      }
      case T_INDEX_TABLE_ID: {
        if (is_index_option && stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else {
            uint64_t table_id = static_cast<uint64_t>(option_node->children_[0]->value_);
            // bool is_sync_ddl_user = false;
            // if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
            //   LOG_WARN("Failed to check check_sync_ddl_user", K(ret));
            // } else if (!is_sync_ddl_user) {
            //   ret = OB_ERR_PARSE_SQL;
            //   LOG_WARN("Only support for sync ddl user to specify index_table_id", K(ret),
            //   K(session_info_->get_user_name()));
            // } else {
            index_table_id_ = table_id;
            // }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("only create index can specify index_table_id for restore purpose", K(ret));
        }
        break;
      }
      case T_VIRTUAL_COLUMN_ID: {
        if (is_index_option && stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option node child is null", K(option_node->children_[0]), K(ret));
          } else {
            bool is_sync_ddl_user = false;
            if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
              LOG_WARN("Failed to check check_sync_ddl_user", K(ret));
            } else if (!is_sync_ddl_user) {
              ret = OB_ERR_PARSE_SQL;
              LOG_WARN("Only support for sync ddl user to specify index_table_id",
                  K(ret),
                  K(session_info_->get_user_name()));
            } else {
              virtual_column_id_ = static_cast<uint64_t>(option_node->children_[0]->value_);
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("only create index can sepcify virtual column id for restore purpose", K(ret));
        }
        break;
      }
      case T_MAX_USED_PART_ID: {
        bool is_sync_ddl_user = false;
        if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          ret = OB_ERR_PARSE_SQL;
          SQL_RESV_LOG(WARN, "not support alter table with max_used_part_id", K(ret));
        } else if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
        } else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
          SQL_RESV_LOG(WARN, "Failed to check sync_dll_user", K(ret));
        } else if (!is_sync_ddl_user) {
          ret = OB_ERR_PARSE_SQL;
          SQL_RESV_LOG(WARN,
              "only support for sync ddl user to create table with max_used_part_id",
              K(ret),
              K(session_info_->get_user_name()));
        } else {
          max_used_part_id_ = static_cast<int64_t>(option_node->children_[0]->value_);
        }
        break;
      }
      case T_PRIMARY_ZONE: {
        if (!is_index_option) {
          ObString tmp_str;
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
          } else if (T_DEFAULT == option_node->children_[0]->type_) {
            if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
              ret = OB_OP_NOT_ALLOW;
              SQL_RESV_LOG(WARN, "set primary_zone DEFAULT is not allowed now", K(ret));
              LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set primary_zone DEFAULT");
            }
          } else if (T_RANDOM == option_node->children_[0]->type_) {
            if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
              ret = OB_OP_NOT_ALLOW;
              SQL_RESV_LOG(WARN, "set primary_zone RANDOM is not allowed now", K(ret));
              LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set primary_zone RANDOM");
            } else {
              primary_zone_.assign_ptr(
                  common::OB_RANDOM_PRIMARY_ZONE, static_cast<int32_t>(strlen(common::OB_RANDOM_PRIMARY_ZONE)));
            }
          } else {
            tmp_str.assign_ptr(const_cast<char*>(option_node->children_[0]->str_value_),
                static_cast<int32_t>(option_node->children_[0]->str_len_));
            primary_zone_ = tmp_str.trim();
            if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2000 && primary_zone_.empty()) {
              ret = OB_OP_NOT_ALLOW;
              SQL_RESV_LOG(WARN, "set primary_zone empty is not allowed now", K(ret));
              LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set primary_zone empty");
            }
          }
          if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            bool is_sync_ddl_user = false;
            if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
              LOG_WARN("Failed to check check_sync_ddl_user", K(ret));
            } else if (is_sync_ddl_user) {
              ret = OB_IGNORE_SQL_IN_RESTORE;
              LOG_WARN(
                  "Cannot support for sync ddl user to alter primary zone", K(ret), K(session_info_->get_user_name()));
            } else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::PRIMARY_ZONE))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify primary zone", K(ret));
        }
        break;
      }
      case T_READ_ONLY: {
        if (!is_index_option) {
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(ERROR, "read only options can not be null", K(ret));
          } else if (T_ON == option_node->children_[0]->type_) {
            read_only_ = true;
          } else if (T_OFF == option_node->children_[0]->type_) {
            read_only_ = false;
          } else {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "unknown read only options", K(ret));
          }
          if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(obrpc::ObAlterTableArg::READ_ONLY))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify read only", K(ret));
        }
        break;
      }
      case T_AUTO_INCREMENT: {
        if (!is_index_option) {
          // parser filters negative value
          errno = 0;
          int err = 0;
          uint64_t auto_increment = 0;
          if (OB_ISNULL(option_node->children_[0])) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(ERROR, "read only options can not be null", K(ret));
          } else {
            auto_increment = ObCharset::strntoull(option_node->children_[0]->str_value_,
                static_cast<int32_t>(option_node->children_[0]->str_len_),
                10,
                &err);
          }
          /* If the value read is out of the range of representable values by a long long int,
           * the function returns LLONG_MAX or LLONG_MIN, and errno is set to ERANGE.
           */
          if (OB_FAIL(ret)) {
            // do nothing
          } else if (ERANGE == err && (UINT_MAX == auto_increment || 0 == auto_increment)) {
            ret = OB_DATA_OUT_OF_RANGE;
          } else if (EDOM == err) {
            ObString node_str(
                static_cast<int32_t>(option_node->children_[0]->str_len_), option_node->children_[0]->str_value_);
            ret = OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD;
            SQL_RESV_LOG(WARN, "failed, invalid value", K(auto_increment), K(node_str), K(err), K(ret));
            LOG_USER_ERROR(OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD, node_str.length(), node_str.ptr());
          } else {
            auto_increment_ = auto_increment;
          }
          if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::AUTO_INCREMENT))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not specify autoincrement id", K(ret));
        }
        break;
      }
      case T_TABLE_RENAME: {
        if (!is_index_option) {
          if (stmt::T_ALTER_TABLE != stmt_->get_stmt_type()) {
            ret = OB_ERR_RESOLVE_SQL;
            SQL_RESV_LOG(WARN, "Can't alter table name when creating table", K(ret));
          } else {
            ParseNode* relation_node = NULL;
            ObString new_database_name;
            if (OB_ISNULL(option_node->children_[0])) {
              ret = OB_ERR_UNEXPECTED;
              SQL_RESV_LOG(ERROR, "read only options can not be null", K(ret));
            } else {
              relation_node = option_node->children_[0];
            }

            if (OB_FAIL(ret)) {
            } else if (OB_ISNULL(relation_node)) {
              ret = OB_ERR_PARSE_SQL;
              SQL_RESV_LOG(WARN, "table relation node should not be null!", K(ret));
            } else if (OB_FAIL(resolve_table_relation_node(relation_node, table_name_, new_database_name))) {
            } else if (table_name_.empty()) {
              ret = OB_WRONG_TABLE_NAME;
              LOG_USER_ERROR(OB_WRONG_TABLE_NAME, table_name_.length(), table_name_.ptr());
            } else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLE_NAME))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            } else if (share::is_oracle_mode()) {
              ParseNode* new_db_node = relation_node->children_[0];
              if (OB_ISNULL(new_db_node)) {
                database_name_ = static_cast<ObAlterTableStmt*>(stmt_)->get_org_database_name();
              } else {
                ret = OB_ERR_ALTER_TABLE_RENAME_WITH_OPTION;
                SQL_RESV_LOG(WARN, "new_db_node should be null in oracle mode", K(ret));
              }
            } else {
              database_name_ = new_database_name;
            }
          }
        } else {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("index option should not rename table", K(ret));
        }
        break;
      }
      case T_USING_BTREE: {
        has_index_using_type_ = true;
        index_using_type_ = USING_BTREE;
        break;
      }
      case T_USING_HASH: {
        has_index_using_type_ = true;
        index_using_type_ = USING_HASH;
        break;
      }
      case T_ENGINE: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(ERROR, "engine node can not be null", K(ret));
        } else {
          ObString engine_name(
              static_cast<int32_t>(option_node->children_[0]->str_len_), option_node->children_[0]->str_value_);
          LOG_USER_WARN(OB_ERR_UNKNOWN_STORAGE_ENGINE, engine_name.length(), engine_name.ptr());
          SQL_RESV_LOG(WARN, "unknown engine", K(engine_name), K(ret));
          ret = OB_SUCCESS;
        }
        break;
      }
      case T_INVISIBLE: {
        index_attributes_set_ |= (uint64_t)1 << ObTableSchema::INDEX_VISIBILITY;
        break;
      }
      case T_VISIBLE: {
        /*do nothing default is visible*/
        index_attributes_set_ &= ~((uint64_t)1 << ObTableSchema::INDEX_VISIBILITY);
        break;
      }
      case T_DUPLICATE_SCOPE: {
        ObString duplicate_scope_str;
        share::ObDuplicateScope my_duplicate_scope = share::ObDuplicateScope::DUPLICATE_SCOPE_MAX;
        if (nullptr == option_node->children_ || 1 != option_node->num_child_) {
          ret = common::OB_INVALID_ARGUMENT;
          SQL_RESV_LOG(WARN, "invalid replicate scope arg", K(ret), "num_child", option_node->num_child_);
        } else if (nullptr == option_node->children_[0]) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option node child is null", K(ret));
        } else {
          duplicate_scope_str.assign_ptr(const_cast<char*>(option_node->children_[0]->str_value_),
              static_cast<int32_t>(option_node->children_[0]->str_len_));
          duplicate_scope_str = duplicate_scope_str.trim();
          if (OB_FAIL(
                  ObDuplicateScopeChecker::convert_duplicate_scope_string(duplicate_scope_str, my_duplicate_scope))) {
            SQL_RESV_LOG(WARN, "fail to convert replicate scope string", K(ret));
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "duplicate_scope");
          } else {
            duplicate_scope_ = my_duplicate_scope;
          }
          if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::DUPLICATE_SCOPE))) {
              LOG_WARN("fail to add member to bitset!", K(ret));
            }
          }
        }
        break;
      }
      case T_LOCALITY: {
        if (NULL == option_node->children_ || option_node->num_child_ != 2) {
          ret = common::OB_INVALID_ARGUMENT;
          SQL_RESV_LOG(WARN, "invalid locality argument", K(ret), "num_child", option_node->num_child_);
        } else if (T_DEFAULT == option_node->children_[0]->type_) {
          if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
            ret = OB_OP_NOT_ALLOW;
            SQL_RESV_LOG(WARN, "set locality DEFAULT is not allowed now", K(ret));
            LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set locality DEFAULT");
          }
        } else {
          int64_t locality_length = option_node->children_[0]->str_len_;
          const char* locality_str = option_node->children_[0]->str_value_;
          common::ObString locality(locality_length, locality_str);
          if (OB_UNLIKELY(locality_length > common::MAX_LOCALITY_LENGTH)) {
            ret = common::OB_ERR_TOO_LONG_IDENT;
            SQL_RESV_LOG(WARN, "locality length is beyond limit", K(ret), K(locality));
            LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, locality.length(), locality.ptr());
          } else if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2000 && 0 == locality_length) {
            ret = OB_OP_NOT_ALLOW;
            SQL_RESV_LOG(WARN, "set locality empty is not allowed now", K(ret));
            LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set locality empty");
          } else {
            locality_.assign_ptr(locality_str, static_cast<int32_t>(locality_length));
          }
        }
        if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          bool is_sync_ddl_user = false;
          if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
            LOG_WARN("Failed to check sync_dll_user", K(ret));
          } else if (is_sync_ddl_user) {
            ret = OB_IGNORE_SQL_IN_RESTORE;
            LOG_WARN("Cannot support for sync ddl user to alter locality", K(ret), K(session_info_->get_user_name()));
          } else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::LOCALITY))) {
            SQL_RESV_LOG(WARN, "fail to add member to bitset!", K(ret));
          } else if (nullptr == option_node->children_[1]) {
            // not force alter locality
          } else if (option_node->children_[1]->type_ != T_FORCE) {
            ret = common::OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(ERROR, "invalid node", K(ret));
          } else if (OB_FAIL(alter_table_bitset_.add_member(obrpc::ObAlterTableArg::FORCE_LOCALITY))) {
            SQL_RESV_LOG(WARN, "fail to add force locality member to bitset", K(ret));
          }
        }
        break;
      }
      case T_ENABLE_ROW_MOVEMENT: {
        if (NULL == option_node->children_ || 1 != option_node->num_child_ ||
            T_BOOL != option_node->children_[0]->type_) {
          ret = common::OB_INVALID_ARGUMENT;
          SQL_RESV_LOG(WARN, "invalid row movement argument", K(ret), "num_child", option_node->num_child_);
        } else {
          enable_row_movement_ = static_cast<bool>(option_node->children_[0]->value_);
          if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
            if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::ENABLE_ROW_MOVEMENT))) {
              SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
            }
          }
        }
        break;
      }
      case T_PARALLEL: {
        if (OB_ISNULL(option_node->children_[0])) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
        } else {
          const int64_t table_dop = option_node->children_[0]->value_;
          if (table_dop <= 0) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "invalid table dop", K(table_dop), K(ret));
          } else {
            table_dop_ = table_dop;
          }
        }
        if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
          if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLE_DOP))) {
            SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
          }
        }
        break;
      }
      default: {
        /* won't be here */
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(ERROR, "should not reach here", K(option_node->type_), K(ret));
        break;
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_column_definition_ref(
    ObColumnSchemaV2& column, ParseNode* node /* column_definition_def */, bool is_resolve_for_alter_table)
{
  int ret = OB_SUCCESS;
  ObString name;
  int32_t name_length = 0;
  const char* name_ptr = nullptr;
  if (OB_ISNULL(node)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid parser tree!", K(ret), K(node));
  } else if (T_COLUMN_REF != node->type_ || 3 != node->num_child_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid parser tree!", K(ret), K(node->type_), K(node->num_child_));
  } else {
    ParseNode* db_name_node = node->children_[0];
    ParseNode* table_name_node = node->children_[1];
    if (is_oracle_mode()) {
      if (OB_NOT_NULL(table_name_node) || OB_NOT_NULL(db_name_node)) {
        ret = OB_ERR_ONLY_SIMPLE_COLUMN_NAME_ALLOWED;
        LOG_WARN("only simple column names allowed here", K(ret));
      }
    } else {
      if (NULL != db_name_node) {
        ObString dbname(db_name_node->str_len_, db_name_node->str_value_);
        if (0 != dbname.compare(database_name_)) {
          ret = OB_WRONG_DB_NAME;
          LOG_WARN("invalid database name", K(ret));
          LOG_USER_ERROR(OB_WRONG_DB_NAME, dbname.length(), dbname.ptr());
        }
      }
      if (OB_FAIL(ret)) {
      } else if (NULL != table_name_node) {
        ObString table_name(table_name_node->str_len_, table_name_node->str_value_);
        if (0 != table_name.compare(table_name_)) {
          ret = OB_WRONG_TABLE_NAME;
          LOG_WARN("invalid table name", K(ret));
          LOG_USER_ERROR(OB_WRONG_TABLE_NAME, table_name.length(), table_name.ptr());
        }
      }
    }
  }
  if (OB_FAIL(ret)) {
  } else if (OB_FAIL(resolve_column_name(name, node->children_[2]))) {
    LOG_WARN("resolve column name failed", K(ret));
  } else if (is_resolve_for_alter_table) {
    AlterColumnSchema& alter_column_schema = static_cast<AlterColumnSchema&>(column);
    if (OB_FAIL(alter_column_schema.set_origin_column_name(name))) {
      SQL_RESV_LOG(WARN, "fail to set origin column name", K(name), K(ret));
    }
  } else if (OB_FAIL(column.set_column_name(name))) {
    SQL_RESV_LOG(WARN, "fail to set column name", K(name), K(ret));
  }
  return ret;
}

int ObDDLResolver::resolve_column_name(common::ObString& col_name, ParseNode* node /* column_name */)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node) || T_IDENT != node->type_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid parser tree", K(ret));
  } else {
    col_name.assign_ptr(node->str_value_, node->str_len_);
    int32_t name_length = col_name.length();
    const char* name_ptr = col_name.ptr();
    if (name_length > OB_MAX_COLUMN_NAME_LENGTH) {
      ret = OB_ERR_TOO_LONG_IDENT;
      _SQL_RESV_LOG(
          WARN, "identifier name '%.*s' is too long, ret=%d", static_cast<int32_t>(name_length), name_ptr, ret);
      LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, static_cast<int32_t>(name_length), name_ptr);
    } else if (0 == name_length) {
      ret = OB_WRONG_COLUMN_NAME;
      _SQL_RESV_LOG(WARN, "identifier name '%.*s' is empty, ret=%d", static_cast<int32_t>(name_length), name_ptr, ret);
      LOG_USER_ERROR(OB_WRONG_COLUMN_NAME, static_cast<int32_t>(name_length), name_ptr);
    } else {
      ObCollationType cs_type = CS_TYPE_INVALID;
      if (share::is_oracle_mode() && 0 == col_name.case_compare(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME)) {
        ret = OB_ERR_BAD_FIELD_ERROR;
        LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, name_length, name_ptr, table_name_.length(), table_name_.ptr());
        LOG_WARN("invalid rowid column", K(ret));
      } else if (OB_FAIL(session_info_->get_collation_connection(cs_type))) {
        LOG_WARN("fail to get collation_connection", K(ret));
      } else if (OB_FAIL(ObSQLUtils::check_column_name(cs_type, col_name))) {
        SQL_RESV_LOG(WARN, "fail to check column name", K(col_name), K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_column_definition(ObColumnSchemaV2& column, ParseNode* node, /* column_definition */
    ObColumnResolveStat& resolve_stat, bool& is_modify_column_visibility, common::ObString& pk_name,
    const bool is_add_column, const bool is_modify_column, const bool is_oracle_temp_table,
    const bool is_create_table_as)
{
  int ret = OB_SUCCESS;
  ParseNode* column_definition_ref_node = NULL;
  if (T_COLUMN_DEFINITION != node->type_ || node->num_child_ < COLUMN_DEFINITION_NUM_CHILD || OB_ISNULL(allocator_) ||
      OB_ISNULL(node->children_) || OB_ISNULL(node->children_[0]) || T_COLUMN_REF != node->children_[0]->type_ ||
      COLUMN_DEF_NUM_CHILD != node->children_[0]->num_child_ || OB_ISNULL(session_info_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(
        WARN, "invalid parse node", K(ret), K(node->type_), K(node->num_child_), K_(allocator), K_(session_info));
  } else {
    resolve_stat.reset();
    column_definition_ref_node = node->children_[0];
    ParseNode* table_node = column_definition_ref_node->children_[1];
    if (is_oracle_mode() && OB_NOT_NULL(table_node)) {
      ret = OB_ERR_ONLY_SIMPLE_COLUMN_NAME_ALLOWED;
      LOG_WARN("only simple column names allowed here", K(ret));
    } else if (OB_SUCC(resolve_column_definition_ref(column, column_definition_ref_node, false))) {
      // empty
    } else {
      SQL_RESV_LOG(WARN, "fail to resolve column_definition_ref", K(ret));
    }
  }
  ParseNode* type_node = NULL;
  if (OB_SUCC(ret)) {
    type_node = node->children_[1];
    if (OB_ISNULL(type_node)) {
      if (share::is_oracle_mode() &&
          (is_modify_column || GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_ || is_create_table_as)) {
        // allow data_type node to be null in Oracle mode
        //  1. alter table column
        //  2. generated column def
        //  3. create table as
        if (is_create_table_as) {
          // mock a dummy data_type, will override in resolve subquery phase
          ObDataType data_type;
          column.set_data_type(ObUInt64Type);
          column.set_charset_type(CHARSET_BINARY);
          column.set_collation_type(CS_TYPE_BINARY);
        }
      } else {
        ret = OB_ERR_INVALID_DATATYPE;
        LOG_WARN("type_node is invalid", K(ret));
      }
    } else if (OB_UNLIKELY(!ob_is_valid_obj_type(static_cast<ObObjType>(type_node->type_)))) {
      ret = OB_ERR_INVALID_DATATYPE;
      SQL_RESV_LOG(WARN, "type_node or stmt_ or datatype is invalid", K(ret));
    }
  }
  if (OB_SUCC(ret) && type_node != NULL) {
    ObDataType data_type;
    if (OB_FAIL(ObResolverUtils::resolve_data_type(*type_node,
            column.get_column_name_str(),
            data_type,
            (OB_NOT_NULL(session_info_) && is_oracle_mode()),
            session_info_->get_session_nls_params()))) {
      LOG_WARN("resolve data type failed", K(ret), K(column.get_column_name_str()));
    } else if (ObExtendType == data_type.get_obj_type()) {
      ret = OB_NOT_SUPPORTED;
    } else {
      column.set_meta_type(data_type.get_meta_type());
      column.set_accuracy(data_type.get_accuracy());
      column.set_charset_type(data_type.get_charset_type());
      column.set_collation_type(data_type.get_collation_type());
      if (data_type.is_binary_collation()) {
        column.set_binary_collation(true);
        column.set_collation_type(CS_TYPE_INVALID);
      }
      if (data_type.get_meta_type().is_integer_type() || data_type.get_meta_type().is_numeric_type()) {
        column.set_zero_fill(data_type.is_zero_fill());
      }
      if (ob_is_nstring_type(column.get_meta_type().get_type())) {
        CK(OB_NOT_NULL(session_info_));
        if (OB_SUCC(ret)) {
          ObCollationType coll_type = session_info_->get_nls_collation_nation();
          column.set_collation_type(coll_type);
          column.set_charset_type(ObCharset::charset_type_by_coll(coll_type));
        }
      }
      if (OB_SUCC(ret) && column.is_string_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
        if (OB_FAIL(check_and_fill_column_charset_info(column, charset_type_, collation_type_))) {
          SQL_RESV_LOG(WARN, "fail to check and fill column charset info", K(ret));
        } else if (data_type.get_meta_type().is_lob()) {
          if (OB_FAIL(check_text_column_length_and_promote(column))) {
            SQL_RESV_LOG(WARN, "fail to check text or blob column length", K(ret), K(column));
          }
        } else if (OB_FAIL(check_string_column_length(column, lib::is_oracle_mode()))) {
          SQL_RESV_LOG(WARN, "fail to check string column length", K(ret), K(column));
        }
      }
      if (OB_SUCC(ret) && ObRawType == column.get_data_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
        if (OB_FAIL(ObDDLResolver::check_raw_column_length(column))) {
          SQL_RESV_LOG(WARN, "failed to check raw column length", K(ret), K(column));
        }
      }
      if (OB_SUCC(ret) && ObURowIDType == column.get_data_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
        if (OB_FAIL(ObDDLResolver::check_urowid_column_length(column))) {
          SQL_RESV_LOG(WARN, "failed to check rowid column length", K(ret));
        }
      }
      if (OB_SUCC(ret) && column.is_enum_or_set()) {
        if (OB_FAIL(resolve_enum_or_set_column(type_node, column))) {
          LOG_WARN("fail to resolve set column", K(ret), K(column));
        }
      }
    }
  }
  if (OB_SUCC(ret) && GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_) {
    ParseNode* expr_node = NULL;
    if (share::is_oracle_mode() && (column.get_meta_type().is_blob() || column.get_meta_type().is_clob())) {
      ret = OB_ERR_INVALID_VIRTUAL_COLUMN_TYPE;
      LOG_WARN("invalid use of blob/clob type with generate defnition", K(ret), K(column.get_meta_type()));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "generate column with blob type");
    } else if (share::is_oracle_mode() && is_create_table_as) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("generate column in create table as not support", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "generate column in create table as");
    } else if (OB_ISNULL(expr_node = node->children_[3])) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("expr_node is null");
    } else {
      ObString expr_str(expr_node->str_len_, expr_node->str_value_);
      ObObj default_value;
      default_value.set_varchar(expr_str);
      default_value.set_collation_type(ObCharset::get_system_collation());
      if (OB_FAIL(column.set_cur_default_value(default_value))) {
        LOG_WARN("set current default value failed", K(ret));
      } else if (node->children_[4] != NULL && node->children_[4]->type_ == T_STORED_COLUMN) {
        column.add_column_flag(STORED_GENERATED_COLUMN_FLAG);
      } else {
        column.add_column_flag(VIRTUAL_GENERATED_COLUMN_FLAG);
      }
    }
  }
  if (OB_SUCC(ret)) {
    ParseNode* attrs_node = node->children_[2];
    if (attrs_node != NULL) {
      if (OB_UNLIKELY(6 == node->num_child_)) {
        if (OB_FAIL(resolve_generated_column_attribute(column, attrs_node, resolve_stat))) {
          LOG_WARN("resolve generated column attribute failed", K(ret));
        }
      } else if (OB_FAIL(resolve_normal_column_attribute(column, attrs_node, resolve_stat, pk_name))) {
        LOG_WARN("resolve normal column attribute failed", K(ret));
      }
    }
    // specify column pos, only supported in add column syntax within MySQL Mode
    if (OB_SUCC(ret) && share::is_mysql_mode()) {
      ParseNode* pos_node = NULL;
      if (OB_UNLIKELY(GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_)) {
        // generated column with pos_column
        pos_node = node->children_[5];
      } else {
        // normal column with pos_column
        pos_node = node->children_[3];
      }
      if (NULL != pos_node) {
        if (!is_add_column) {
          ret = OB_NOT_SUPPORTED;
          SQL_RESV_LOG(WARN, "unsupport for first or before or after column", K(ret));
        }
      }
    }
    // visibility_option, Oracle mode only
    if (OB_SUCC(ret) && share::is_oracle_mode()) {
      ParseNode* visiblity_node = NULL;
      if (OB_UNLIKELY(GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_)) {
        visiblity_node = node->children_[5];
      } else {
        visiblity_node = node->children_[3];
      }
      if (NULL != visiblity_node) {
        if (is_modify_column) {
          // Column visibility modifications can not be combined with any other modified column DDL option.
          if (OB_UNLIKELY(GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_)) {
            visiblity_node = node->children_[5];
            if (OB_NOT_NULL(node->children_[1]) || OB_NOT_NULL(node->children_[2]) || OB_NOT_NULL(node->children_[3]) ||
                OB_NOT_NULL(node->children_[4])) {
              ret = OB_ERR_MODIFY_COL_VISIBILITY_COMBINED_WITH_OTHER_OPTION;
              SQL_RESV_LOG(WARN,
                  "Column visibility modifications can not be combined with any other modified column DDL option.",
                  K(ret));
            } else {
              is_modify_column_visibility = true;
            }
          } else {
            if (OB_NOT_NULL(node->children_[1]) || OB_NOT_NULL(node->children_[2])) {
              ret = OB_ERR_MODIFY_COL_VISIBILITY_COMBINED_WITH_OTHER_OPTION;
              SQL_RESV_LOG(WARN,
                  "Column visibility modifications can not be combined with any other modified column DDL option.",
                  K(ret));
            } else {
              is_modify_column_visibility = true;
            }
          }
        }
        if (OB_SUCC(ret)) {
          if (T_INVISIBLE == visiblity_node->type_) {
            const ObTableSchema* table_schema = NULL;
            if (is_oracle_temp_table) {
              ret = OB_ERR_INVISIBLE_COL_ON_UNSUPPORTED_TABLE_TYPE;
              LOG_WARN("Invisible column is not supported on temp table.", K(ret));
            } else if (OB_ISNULL(schema_checker_)) {
              ret = OB_ERR_UNEXPECTED;
              LOG_WARN("schema checker ptr is null", K(ret));
            } else if (is_modify_column &&
                       OB_FAIL(schema_checker_->get_table_schema(column.get_table_id(), table_schema))) {
              LOG_WARN("get_table_schema failed", K(ret), K(column.get_table_id()));
            } else if (is_modify_column && is_sys_database_id(table_schema->get_database_id())) {
              // The visibility of a column from a table owned by a SYS user cannot be modified to invisible, but can be
              // modified to visible
              ret = OB_ERR_MODIFY_COL_VISIBILITY_BY_SYS_USER;
              SQL_RESV_LOG(
                  WARN, "The visibility of a column from a table owned by a SYS user cannot be changed.", K(ret));
            } else {
              column.add_column_flag(INVISIBLE_COLUMN_FLAG);
            }
          } else {
            // T_VISIBLE == visiblity_node->type_
            column.del_column_flag(INVISIBLE_COLUMN_FLAG);
          }
        }
      }
    }
  }
  return ret;
}

// only use in oracle mode
int ObDDLResolver::resolve_uk_name_from_column_attribute(ParseNode* attrs_node, common::ObString& uk_name)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(attrs_node)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("attrs_node is invalid");
  }
  for (int64_t i = 0; OB_SUCC(ret) && i < attrs_node->num_child_; ++i) {
    ParseNode* attr_node = attrs_node->children_[i];
    if (T_CONSTR_UNIQUE_KEY != attr_node->type_) {
      continue;
    } else {
      ParseNode* uk_name_node = attr_node->children_[0];
      if (OB_ISNULL(uk_name_node)) {
        // do nothing
      } else {
        uk_name.assign_ptr(uk_name_node->str_value_, static_cast<int32_t>(uk_name_node->str_len_));
      }
      break;
    }
  }

  return ret;
}

int ObDDLResolver::resolve_normal_column_attribute(
    ObColumnSchemaV2& column, ParseNode* attrs_node, ObColumnResolveStat& resolve_stat, ObString& pk_name)
{
  int ret = OB_SUCCESS;
  ObObjParam default_value;
  default_value.set_null();
  bool is_set_cur_default = false;
  bool is_set_orig_default = false;
  ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);

  if (OB_ISNULL(attrs_node)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("attrs_node is invalid");
  }
  for (int64_t i = 0; OB_SUCC(ret) && i < attrs_node->num_child_; ++i) {
    ParseNode* attr_node = attrs_node->children_[i];
    switch (attr_node->type_) {
      case T_CONSTR_NOT_NULL:
        column.set_nullable(false);
        resolve_stat.is_set_not_null_ = true;
        break;
      case T_CONSTR_NULL:
        // set non_primary_key_column to nullable
        if (!resolve_stat.is_primary_key_) {
          column.set_nullable(true);
        }
        resolve_stat.is_set_null_ = true;
        break;
      case T_CONSTR_PRIMARY_KEY: {
        resolve_stat.is_primary_key_ = true;
        // primary key should not be nullable
        column.set_nullable(false);
        if (ob_is_text_tc(column.get_data_type())) {
          ret = OB_ERR_WRONG_KEY_COLUMN;
          LOG_USER_ERROR(
              OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
          SQL_RESV_LOG(WARN, "BLOB, TEXT column can't be primary key", K(column), K(ret));
        } else if (ObTimestampTZType == column.get_data_type()) {
          ret = OB_ERR_WRONG_KEY_COLUMN;
          LOG_USER_ERROR(
              OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
          SQL_RESV_LOG(WARN, "TIMESTAMP WITH TIME ZONE column can't be primary key", K(column), K(ret));
        }
        if (OB_FAIL(ret)) {
        } else if (share::is_oracle_mode()) {
          ParseNode* pk_name_node = attr_node->children_[0];
          if (OB_ISNULL(pk_name_node)) {
            // do nothing
          } else {
            pk_name.assign_ptr(pk_name_node->str_value_, static_cast<int32_t>(pk_name_node->str_len_));
          }
        }
        break;
      }
      case T_CONSTR_UNIQUE_KEY: {
        resolve_stat.is_unique_key_ = true;
        if (ob_is_text_tc(column.get_data_type())) {
          ret = OB_ERR_WRONG_KEY_COLUMN;
          LOG_USER_ERROR(
              OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
          SQL_RESV_LOG(WARN, "BLOB, TEXT column can't be unique key", K(column), K(ret));
        } else if (ObTimestampTZType == column.get_data_type()) {
          ret = OB_ERR_WRONG_KEY_COLUMN;
          LOG_USER_ERROR(
              OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
          SQL_RESV_LOG(WARN, "TIMESTAMP WITH TIME ZONE column can't be unique key", K(column), K(ret));
        }
        break;
      }
      case T_CONSTR_ORIG_DEFAULT:
      case T_CONSTR_DEFAULT: {
        if (share::is_oracle_mode()) {
          resolve_stat.is_set_default_value_ = true;
          ObString expr_str(attr_node->str_len_, attr_node->str_value_);
          if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(*allocator_,
                  expr_str,
                  expr_str,
                  session_info_->get_local_collation_connection(),
                  CS_TYPE_UTF8MB4_BIN))) {
            LOG_WARN("fail to copy and convert string charset", K(ret));
          } else {
            default_value.set_varchar(expr_str);
            default_value.set_collation_type(CS_TYPE_UTF8MB4_BIN);
            default_value.set_param_meta();
            if (T_CONSTR_ORIG_DEFAULT == attr_node->type_) {
              ret = OB_NOT_SUPPORTED;
              // TODO: do it next
              LOG_WARN("not support set orig default now", K(ret));
            } else if (OB_FAIL(column.set_cur_default_value(default_value))) {
              LOG_WARN("set current default value failed", K(ret));
            } else {
              column.add_column_flag(DEFAULT_EXPR_V2_COLUMN_FLAG);
            }
          }
        } else {
          if (1 != attr_node->num_child_ || NULL == attr_node->children_[0]) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN, "resolve default value failed", K(ret));
          } else if (OB_FAIL(resolve_default_value(attr_node, default_value))) {
            SQL_RESV_LOG(WARN, "resolve default value failed", K(ret));
          } else if (IS_DEFAULT_NOW_OBJ(default_value)) {
            if ((ObDateTimeTC != column.get_data_type_class() && ObOTimestampTC != column.get_data_type_class()) ||
                default_value.get_scale() != column.get_accuracy().get_scale()) {
              ret = OB_INVALID_DEFAULT;
              LOG_USER_ERROR(
                  OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
              SQL_RESV_LOG(WARN, "Invalid default value", K(column), K(default_value), K(ret));
            } else {
              default_value.set_scale(column.get_accuracy().get_scale());
            }
          }

          if (OB_FAIL(ret)) {
            // do nothing
          } else if (!default_value.is_null() && ob_is_text_tc(column.get_data_type())) {
            ret = OB_INVALID_DEFAULT;
            LOG_USER_ERROR(
                OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
            SQL_RESV_LOG(WARN, "BLOB, TEXT column can't have a default value", K(column), K(default_value), K(ret));
          } else {
            if (T_CONSTR_DEFAULT == attr_node->type_) {
              resolve_stat.is_set_default_value_ = true;
              if (is_set_cur_default) {
                ret = OB_ERR_PARSER_SYNTAX;
                SQL_RESV_LOG(WARN, "cannot set current default value twice", K(ret));
              } else {
                is_set_cur_default = true;
                column.set_cur_default_value(default_value);
              }
            } else {
              // T_CONSTR_ORIG_DEFAULT == column.get_data_type_class()
              resolve_stat.is_set_orig_default_value_ = true;
              bool is_sync_ddl_user = false;
              if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
                LOG_WARN("Failed to check sync_dll_user", K(ret));
              } else if (!is_sync_ddl_user || stmt::T_CREATE_TABLE != stmt_->get_stmt_type()) {
                ret = OB_ERR_PARSER_SYNTAX;
                SQL_RESV_LOG(WARN, "Only support for sync ddl user to specify the orig_default_value", K(ret));
              } else if (is_set_orig_default) {
                ret = OB_ERR_PARSER_SYNTAX;
                SQL_RESV_LOG(WARN, "cannot set orig default value twice", K(ret));
              } else {
                is_set_orig_default = true;
                column.set_orig_default_value(default_value);
              }
            }
          }
        }
        LOG_DEBUG("finish resolve default value",
            K(ret),
            K(default_value),
            K(column),
            K(attr_node->num_child_),
            K(attr_node->param_num_));
        break;
      }
      case T_CONSTR_AUTO_INCREMENT:
        if (ob_is_text_tc(column.get_data_type())) {
          ret = OB_ERR_COLUMN_SPEC;
          LOG_USER_ERROR(OB_ERR_COLUMN_SPEC, column.get_column_name_str().length(), column.get_column_name_str().ptr());
          SQL_RESV_LOG(WARN, "BLOB, TEXT column can't set autoincrement", K(column), K(default_value), K(ret));
        } else {
          column.set_autoincrement(true);
          resolve_stat.is_autoincrement_ = true;
        }
        break;
      case T_COLUMN_ID: {
        bool is_sync_ddl_user = false;
        if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
          LOG_WARN("Failed to check sync_dll_user", K(ret));
        } else if (!is_sync_ddl_user && !GCONF.enable_sys_table_ddl) {
          ret = OB_ERR_PARSE_SQL;
          LOG_WARN("Only support for sync ddl user or inner_table add column to specify column id",
              K(ret),
              K(session_info_->get_user_name()));
        } else if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
                   T_INT != attr_node->children_[0]->type_) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "invalid node", K(attr_node->children_[0]), K(ret));
        } else {
          const uint64_t column_id = static_cast<uint64_t>(attr_node->children_[0]->value_);
          // 1. column id must start with 16
          // 2. shadow column for uniq index must start with 32768(32767+1)
          if (column_id < OB_APP_MIN_COLUMN_ID || column_id > OB_MIN_SHADOW_COLUMN_ID) {
            ret = OB_INVALID_ARGUMENT;
            SQL_RESV_LOG(WARN, "invalid column id", K(column_id), K(ret));
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "column id");
          } else {
            column.set_column_id(column_id);
          }
        }
        break;
      }
      case T_COMMENT: {
        if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
            T_VARCHAR != attr_node->children_[0]->type_) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "invalid node!", K(ret));
        } else {
          ObString comment(attr_node->children_[0]->str_len_, attr_node->children_[0]->str_value_);
          ObCollationType client_cs_type = session_info_->get_local_collation_connection();
          if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
                  *allocator_, comment, comment, client_cs_type, CS_TYPE_UTF8MB4_BIN))) {
            LOG_WARN("fail to convert comment to utf8", K(ret), K(comment));
          } else if (comment.length() >= MAX_COLUMN_COMMENT_LENGTH) {
            ret = OB_ERR_TOO_LONG_FIELD_COMMENT;
            LOG_USER_ERROR(OB_ERR_TOO_LONG_FIELD_COMMENT, MAX_COLUMN_COMMENT_LENGTH);
          } else {
            column.set_comment(comment);
          }
        }
        break;
      }
      case T_ON_UPDATE:
        if (ObDateTimeType == column.get_data_type() || ObTimestampType == column.get_data_type()) {
          if (T_FUN_SYS_CUR_TIMESTAMP != attr_node->children_[0]->type_) {
            ret = OB_ERR_PARSER_SYNTAX;
            SQL_RESV_LOG(WARN,
                "on_update attribute can only be timestamp or synonyms type",
                "node_type",
                attr_node->children_[0]->type_,
                K(column),
                K(ret));
          } else {
            int16_t scale = 0;
            if (OB_UNLIKELY(NULL == attr_node->children_[0] || 1 != attr_node->children_[0]->num_child_)) {
              ret = OB_INVALID_ON_UPDATE;
              LOG_WARN("invalid argument", K(ret), K(attr_node->children_[0]));
            } else {
              if (NULL != attr_node->children_[0]->children_[0]) {
                scale = static_cast<int16_t>(attr_node->children_[0]->children_[0]->value_);
              } else {
                // defaule value
              }
              if (column.get_accuracy().get_scale() != scale) {
                ret = OB_INVALID_ON_UPDATE;
                LOG_USER_ERROR(OB_INVALID_ON_UPDATE, column.get_column_name());
                SQL_RESV_LOG(WARN, "Invalid ON UPDATE clause for ", K(column), K(ret));
              } else {
                column.set_on_update_current_timestamp(true);
              }
            }
          }
        } else {
          ret = OB_INVALID_ON_UPDATE;
          LOG_USER_ERROR(OB_INVALID_ON_UPDATE, column.get_column_name());
          SQL_RESV_LOG(WARN,
              "only ObDateTimeType and ObTimeStampType column can have attribute"
              " of on_update",
              K(column),
              K(ret));
        }
        break;
      case T_CHECK_CONSTRAINT: {
        if (stmt::T_CREATE_TABLE != stmt_->get_stmt_type()) {
          ret = OB_NOT_SUPPORTED;
          SQL_RESV_LOG(
              WARN, "Adding column-level check cst while altering table not supported", K(ret), K(stmt_->stmt_type_));
          LOG_USER_ERROR(OB_NOT_SUPPORTED, "Add column-level check cst while altering table");
        } else {
          ObSEArray<ObConstraint, 4>& csts = create_table_stmt->get_create_table_arg().constraint_list_;
          if (OB_FAIL(resolve_check_constraint_node(*attr_node, csts, &column))) {
            SQL_RESV_LOG(WARN, "resolve constraint failed", K(ret));
          }
        }
        break;
      }
      case T_FOREIGN_KEY: {
        if (stmt::T_CREATE_TABLE != stmt_->get_stmt_type()) {
          ret = OB_NOT_SUPPORTED;
          SQL_RESV_LOG(
              WARN, "Adding a column-level fk while altering table is not supported", K(ret), K(stmt_->stmt_type_));
          LOG_USER_ERROR(OB_NOT_SUPPORTED, "Adding column-level foreign key constraints while altering table");
        } else {
          ObCreateForeignKeyArg foreign_key_arg;
          if (OB_FAIL(resolve_foreign_key_node(attr_node, foreign_key_arg, false, &column))) {
            SQL_RESV_LOG(WARN, "failed to resolve foreign key node", K(ret));
          } else if (OB_FAIL(create_table_stmt->get_foreign_key_arg_list().push_back(foreign_key_arg))) {
            SQL_RESV_LOG(WARN, "failed to push back foreign key arg", K(ret));
          }
        }
        break;
      }
      default:  // won't be here
        ret = OB_ERR_PARSER_SYNTAX;
        SQL_RESV_LOG(WARN, "Wrong column constraint", K(ret));
        break;
    }
  }
  if (OB_SUCC(ret) && column.get_cur_default_value().is_null() && resolve_stat.is_set_default_value_ &&
      (!column.is_nullable() || resolve_stat.is_primary_key_)) {
    ret = OB_INVALID_DEFAULT;
    LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
    SQL_RESV_LOG(WARN, "Invalid default value", K(column), K(ret));
  }
  // can't set both null & not null attribute at the same time
  // mysql did not throw error, but it is mysql's bug:
  // http://bugs.mysql.com/bug.php?id=79645
  if (OB_SUCC(ret) && resolve_stat.is_set_null_ && resolve_stat.is_set_not_null_) {
    ret = OB_ERR_COLUMN_DEFINITION_AMBIGUOUS;
    LOG_USER_ERROR(
        OB_ERR_COLUMN_DEFINITION_AMBIGUOUS, column.get_column_name_str().length(), column.get_column_name_str().ptr());
  }
  if (OB_SUCC(ret) && column.is_autoincrement()) {
    if (column.get_cur_default_value().get_type() != ObNullType) {
      ret = OB_INVALID_DEFAULT;
      LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
      SQL_RESV_LOG(WARN, "can not set default value for auto_increment column", K(ret));
    }
    if (OB_SUCC(ret)) {
      // for show create table
      // set auto-increment column default null => still not null
      column.set_nullable(false);
    }
    if (OB_SUCC(ret)) {
      if (column.get_data_type() < ObTinyIntType || column.get_data_type() > ObUDoubleType) {
        ret = OB_ERR_COLUMN_SPEC;
        LOG_USER_ERROR(OB_ERR_COLUMN_SPEC, column.get_column_name_str().length(), column.get_column_name_str().ptr());
        SQL_RESV_LOG(WARN, "wrong column type for auto_increment", K(ret));
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_generated_column_attribute(
    ObColumnSchemaV2& column, ParseNode* attrs_node, ObColumnResolveStat& resolve_stat)
{
  int ret = OB_SUCCESS;
  for (int64_t i = 0; OB_SUCC(ret) && attrs_node && i < attrs_node->num_child_; ++i) {
    ParseNode* attr_node = attrs_node->children_[i];
    switch (attr_node->type_) {
      case T_CONSTR_NOT_NULL:
        column.set_nullable(false);
        resolve_stat.is_set_not_null_ = true;
        break;
      case T_CONSTR_NULL:
        // set non_primary_key_column to nullable
        if (!resolve_stat.is_primary_key_) {
          column.set_nullable(true);
        }
        resolve_stat.is_set_null_ = true;
        break;
      case T_CONSTR_PRIMARY_KEY: {
        //        if (column.is_stored_generated_column()) {
        //          resolve_stat.is_primary_key_ = true;
        // primary key should not be nullable
        //          column.set_nullable(false);
        //        } else {
        ret = OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN;
        LOG_USER_ERROR(OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, "Defining a generated column as primary key");
        //        }
        break;
      }
      case T_CONSTR_UNIQUE_KEY: {
        resolve_stat.is_unique_key_ = true;
        break;
      }
      case T_COMMENT: {
        if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
            T_VARCHAR != attr_node->children_[0]->type_) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "invalid node!", K(ret));
        } else {
          ObString comment(attr_node->children_[0]->str_len_, attr_node->children_[0]->str_value_);
          ObCollationType client_cs_type = session_info_->get_local_collation_connection();
          if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
                  *allocator_, comment, comment, client_cs_type, CS_TYPE_UTF8MB4_BIN))) {
            LOG_WARN("fail to convert comment to utf8", K(ret), K(comment));
          } else if (comment.length() >= MAX_COLUMN_COMMENT_LENGTH) {
            ret = OB_ERR_TOO_LONG_FIELD_COMMENT;
            LOG_USER_ERROR(OB_ERR_TOO_LONG_FIELD_COMMENT, MAX_COLUMN_COMMENT_LENGTH);
          } else {
            column.set_comment(comment);
          }
        }
        break;
      }
      case T_COLUMN_ID: {
        bool is_sync_ddl_user = false;
        if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
            T_INT != attr_node->children_[0]->type_) {
          ret = OB_ERR_UNEXPECTED;
          SQL_RESV_LOG(WARN, "invalid node", K(attr_node->children_[0]), K(ret));
        } else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
          LOG_WARN("Failed to check sync_dll_user", K(ret));
        } else if (!is_sync_ddl_user) {
          ret = OB_ERR_PARSE_SQL;
          LOG_WARN("Only support for sync ddl user to specify column id", K(ret), K(session_info_->get_user_name()));
        } else {
          const uint64_t column_id = static_cast<uint64_t>(attr_node->children_[0]->value_);
          // 1. column id must start with 16
          // 2. shadow column for uniq index must start with 32768(32767+1)
          if (column_id < OB_APP_MIN_COLUMN_ID || column_id > OB_MIN_SHADOW_COLUMN_ID) {
            ret = OB_INVALID_ARGUMENT;
            SQL_RESV_LOG(WARN, "invalid column id", K(column_id), K(ret));
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "column id");
          } else {
            column.set_column_id(column_id);
          }
        }
        break;
      }
      default:  // won't be here
        ret = OB_ERR_PARSER_SYNTAX;
        SQL_RESV_LOG(WARN, "Wrong column constraint", K(ret));
        break;
    }
  }
  // http://bugs.mysql.com/bug.php?id=79645
  if (OB_SUCCESS == ret && resolve_stat.is_set_null_ && resolve_stat.is_set_not_null_) {
    ret = OB_ERR_COLUMN_DEFINITION_AMBIGUOUS;
    LOG_USER_ERROR(
        OB_ERR_COLUMN_DEFINITION_AMBIGUOUS, column.get_column_name_str().length(), column.get_column_name_str().ptr());
  }
  return ret;
}
/*
int ObDDLResolver::resolve_generated_column_definition(ObColumnSchemaV2 &column,
    ParseNode *node, ObColumnResolveStat &resolve_stat)
{
  int ret = OB_SUCCESS;
  ParseNode *name_node = NULL;
  if (T_COLUMN_DEFINITION != node->type_ || node->num_child_ != 6 ||
     OB_ISNULL(allocator_) || OB_ISNULL(node->children_) || OB_ISNULL(node->children_[0]) ||
     T_COLUMN_REF != node->children_[0]->type_ ||
     COLUMN_DEF_NUM_CHILD != node->children_[0]->num_child_){
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "invalid parse node",K(ret));
  } else {
    resolve_stat.reset();
    name_node = node->children_[0]->children_[2];
    if (OB_ISNULL(name_node)) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(ERROR, "name node can not be null", K(ret));
    } else if (OB_FAIL(resolve_column_definition_ref(column, name_node))) {
      SQL_RESV_LOG(WARN, "fail to resolve column_definition_ref", K(ret));
    }
  }
  ParseNode *type_node = NULL;
  if (OB_SUCC(ret)) {
    type_node = node->children_[1];
  }
  if (OB_SUCC(ret) && type_node != NULL) {
    ObDataType data_type;
    const ObLengthSemantics default_length_semantics = LS_BYTE;
    if (OB_FAIL(ObResolverUtils::resolve_data_type(*type_node,
                                                   column.get_column_name_str(),
                                                   data_type,
                                                   (session_info_ != NULL && is_oracle_mode()),
                                                   default_length_semantics))) {
      LOG_WARN("resolve data type failed", K(ret), K(column.get_column_name_str()));
    } else if (ObExtendType == data_type.get_obj_type()) {
      const ParseNode *name_node = type_node->children_[0];
      CK (OB_NOT_NULL(session_info_) && OB_NOT_NULL(schema_checker_));
      CK (OB_NOT_NULL(name_node));
      CK (T_SP_TYPE == name_node->type_);
      if (OB_SUCC(ret)) {
        uint64_t udt_id = OB_INVALID_ID;
        uint64_t db_id = session_info_->get_database_id();
        if (NULL != name_node->children_[0]) {
          OZ (schema_checker_->get_database_id(session_info_->get_effective_tenant_id(),
                                            ObString(name_node->children_[0]->str_len_,
name_node->children_[0]->str_value_), db_id));
        }
        OZ (schema_checker_->get_udt_id(session_info_->get_effective_tenant_id(), db_id, OB_INVALID_ID,
                       ObString(name_node->children_[1]->str_len_, name_node->children_[1]->str_value_), udt_id));
        if (OB_SUCC(ret)) {
          data_type.set_udt_id(udt_id);
        }
      }
    } else { }

    if (OB_SUCC(ret)) {
      column.set_meta_type(data_type.get_meta_type());
      column.set_accuracy(data_type.get_accuracy());
      column.set_charset_type(data_type.get_charset_type());
      if (data_type.is_binary_collation()) {
        column.set_binary_collation(true);
        column.set_collation_type(CS_TYPE_INVALID);
      }
      if (OB_SUCC(ret) && column.is_string_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
        if (OB_FAIL(check_and_fill_column_charset_info(column, charset_type_, collation_type_))) {
          SQL_RESV_LOG(WARN, "fail to check and fill column charset info", K(ret));
        } else if (data_type.get_meta_type().is_lob()) {
          if (OB_FAIL(check_text_column_length_and_promote(column))) {
            SQL_RESV_LOG(WARN, "fail to check text or blob column length", K(ret), K(column));
          }
        } else if (OB_FAIL(check_string_column_length(column, lib::is_oracle_mode()))) {
          SQL_RESV_LOG(WARN, "fail to check string column length", K(ret), K(column));
        }
      }
      if (OB_SUCC(ret) && ObRawType == column.get_data_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
        if (OB_FAIL(ObDDLResolver::check_raw_column_length(column))) {
          SQL_RESV_LOG(WARN, "failed to check raw column length", K(ret), K(column));
        }
      }
    }
  }
  return ret;
}
*/

int ObDDLResolver::cast_default_value(ObObj& default_value, const ObTimeZoneInfo* tz_info,
    const common::ObString* nls_formats, ObIAllocator& allocator, ObColumnSchemaV2& column_schema)
{
  // cast default value
  int ret = OB_SUCCESS;
  const int64_t CUR_TIME = 0;
  bool need_cast = false;

  if (default_value.is_null()) {
    need_cast = false;
  } else if (column_schema.get_data_type() != default_value.get_type()) {
    need_cast = true;
  } else if (column_schema.is_string_type() && default_value.is_string_type() &&
             column_schema.get_collation_type() != default_value.get_collation_type()) {
    need_cast = true;
  }

  if (need_cast) {
    ObAccuracy res_accuracy;
    const ObDataTypeCastParams dtc_params(
        tz_info, nls_formats, CS_TYPE_INVALID, CS_TYPE_INVALID, CS_TYPE_UTF8MB4_GENERAL_CI);
    ObCastCtx cast_ctx(&allocator,
        &dtc_params,
        CUR_TIME,
        share::is_oracle_mode() ? CM_ORACLE_MODE : CM_NONE,
        column_schema.get_collation_type(),
        NULL,
        &res_accuracy);
    if (ob_is_enumset_tc(column_schema.get_data_type())) {
      if (OB_FAIL(cast_enum_or_set_default_value(column_schema, cast_ctx, default_value))) {
        LOG_WARN("fail to cast enum or set default value", K(default_value), K(column_schema), K(ret));
      }
    } else if (IS_DEFAULT_NOW_OBJ(default_value)) {
      if (ObDateTimeTC == column_schema.get_data_type_class()) {
        if (OB_FAIL(column_schema.set_cur_default_value(default_value))) {
          SQL_RESV_LOG(WARN, "set current default value failed", K(ret));
        }
      } else {
        ret = OB_INVALID_DEFAULT;
        LOG_USER_ERROR(OB_INVALID_DEFAULT,
            column_schema.get_column_name_str().length(),
            column_schema.get_column_name_str().ptr());
      }
    } else {
      // so cool. cast in place.
      if (OB_FAIL(ObObjCaster::to_type(column_schema.get_data_type(), cast_ctx, default_value, default_value))) {
        SQL_RESV_LOG(WARN,
            "cast default value failed",
            K(ret),
            "src_type",
            default_value.get_type(),
            "dst_type",
            column_schema.get_data_type(),
            K(ret));
      } else if (ObNumberTC == column_schema.get_data_type_class()) {
        number::ObNumber nmb;
        nmb = default_value.get_number();
        if (share::is_oracle_mode()) {
          const ObObj* res_obj = &default_value;
          const common::ObAccuracy& accuracy = column_schema.get_accuracy();
          if (OB_FAIL(common::obj_accuracy_check(
                  cast_ctx, accuracy, column_schema.get_collation_type(), *res_obj, default_value, res_obj))) {
            SQL_RESV_LOG(WARN, "check and round number failed on oracle mode", K(ret), K(default_value), K(*res_obj));
          }
        } else {
          if (OB_FAIL(nmb.check_and_round(column_schema.get_data_precision(), column_schema.get_data_scale()))) {
            SQL_RESV_LOG(WARN, "check and round number failed", K(ret));
          }
        }
        if (OB_SUCC(ret)) {
          default_value.set_number(column_schema.get_data_type(), nmb);
        }
      }
      if (OB_FAIL(ret)) {
        ret = OB_INVALID_DEFAULT;
        LOG_USER_ERROR(OB_INVALID_DEFAULT,
            column_schema.get_column_name_str().length(),
            column_schema.get_column_name_str().ptr());
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_default_value_length(const ObObj& default_value, const ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  int64_t strlen = -1;
  if (ObStringTC == column.get_data_type_class()) {
    if (CS_TYPE_INVALID == column.get_collation_type()) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(ERROR, "invaild default data type", K(ret));
    } else {
      // get characters of default value under specified charset
      ObString str;
      const bool is_byte_length = is_oracle_byte_length(share::is_oracle_mode(), column.get_length_semantics());
      if (default_value.is_null()) {
        strlen = 0;
      } else if (OB_FAIL(default_value.get_varchar(str))) {
        SQL_RESV_LOG(WARN, "invalid default data", K(ret), K(str), K(default_value));
      } else {
        strlen = is_byte_length ? str.length()
                                : ObCharset::strlen_char(column.get_collation_type(), str.ptr(), str.length());
      }
      if (OB_SUCC(ret) && strlen > column.get_data_length()) {
        ret = OB_INVALID_DEFAULT;
        SQL_RESV_LOG(WARN,
            "Invalid default value: length is larger than data length",
            "default_value",
            str,
            "length",
            strlen,
            "data_length",
            column.get_data_length(),
            K(is_byte_length));
        LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
      }
    }
  } else if (ObBitTC == column.get_data_type_class()) {
    int32_t bit_len = 0;
    if (default_value.is_null()) {
      // do nothing
    } else if (OB_FAIL(get_bit_len(default_value.get_bit(), bit_len))) {
      SQL_RESV_LOG(WARN, "fail to  get bit length", K(ret), K(default_value), K(bit_len));
    } else if (bit_len > column.get_data_precision()) {
      ret = OB_INVALID_DEFAULT;
      SQL_RESV_LOG(WARN,
          "default value length is larger than column length",
          K(ret),
          K(default_value),
          K(bit_len),
          K(column.get_data_precision()));
      LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
    } else { /*do nothing*/
    }
  } else { /*do nothing*/
  }
  return ret;
}

int ObDDLResolver::build_partition_key_info(
    ObTableSchema& table_schema, const bool is_subpart, const bool is_key_implicit_v2)
{
  int ret = OB_SUCCESS;
  ObSEArray<ObQualifiedName, 8> qualified_names;
  ObRawExpr* partition_key_expr = NULL;
  if (OB_FAIL(ObResolverUtils::build_partition_key_expr(
          params_, table_schema, partition_key_expr, &qualified_names, is_key_implicit_v2))) {
    LOG_WARN("failed to build partition key expr!", K(ret));
  } else if (OB_UNLIKELY(qualified_names.count() <= 0)) {
    // no primary key, error now
    ret = OB_ERR_FIELD_NOT_FOUND_PART;
    LOG_WARN("Field in list of fields for partition function not found in table", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < qualified_names.count(); ++i) {
      ObQualifiedName& q_name = qualified_names.at(i);
      if (is_subpart) {
        if (OB_FAIL(table_schema.add_subpartition_key(q_name.col_name_))) {
          LOG_WARN("Failed to add subpartition key", K(ret));
        }
      } else if (OB_FAIL(table_schema.add_partition_key(q_name.col_name_))) {
        LOG_WARN("Failed to add partition key", K(ret));
      } else {
      }  // do nothing
    }
  }
  return ret;
}

int ObDDLResolver::set_partition_keys(
    ObTableSchema& table_schema, ObIArray<ObString>& partition_keys, const bool is_subpart)
{
  int ret = OB_SUCCESS;
  for (int64_t i = 0; OB_SUCC(ret) && i < partition_keys.count(); ++i) {
    if (is_subpart) {
      if (OB_FAIL(table_schema.add_subpartition_key(partition_keys.at(i)))) {
        LOG_WARN("Failed to add subpartition key", K(ret), "key_name", partition_keys.at(i));
      }
    } else if (OB_FAIL(table_schema.add_partition_key(partition_keys.at(i)))) {
      LOG_WARN("Failed to add partition key", K(ret), "key_name", partition_keys.at(i));
    } else {
    }  // do nothing
  }
  return ret;
}

void ObDDLResolver::reset()
{
  block_size_ = OB_DEFAULT_SSTABLE_BLOCK_SIZE;
  consistency_level_ = INVALID_CONSISTENCY;
  index_scope_ = NOT_SPECIFIED;
  replica_num_ = 0;
  tablet_size_ = -1;
  charset_type_ = CHARSET_INVALID;
  collation_type_ = CS_TYPE_INVALID;
  use_bloom_filter_ = false;
  expire_info_.reset();
  compress_method_.reset();
  parser_name_.reset();
  comment_.reset();
  tablegroup_name_.reset();
  primary_zone_.reset();
  row_store_type_ = MAX_ROW_STORE;
  store_format_ = OB_STORE_FORMAT_INVALID;
  progressive_merge_num_ = OB_DEFAULT_PROGRESSIVE_MERGE_NUM;
  storage_format_version_ = OB_STORAGE_FORMAT_VERSION_INVALID;
  table_id_ = OB_INVALID_ID;
  data_table_id_ = OB_INVALID_ID;
  index_table_id_ = OB_INVALID_ID;
  partition_func_type_ = PARTITION_FUNC_TYPE_HASH;
  auto_increment_ = 1;
  index_name_.reset();
  index_keyname_ = NORMAL_KEY;
  global_ = true;
  store_column_names_.reset();
  hidden_store_column_names_.reset();
  sort_column_array_.reset();
  storing_column_set_.reset();
  fulltext_column_names_.reset();
  fulltext_column_set_.reset();
  locality_.reset();
  is_random_primary_zone_ = false;
  max_used_part_id_ = OB_INVALID_ID;
  enable_row_movement_ = false;
  table_mode_.reset();
  table_dop_ = DEFAULT_TABLE_DOP;
  hash_subpart_num_ = -1;
}

bool ObDDLResolver::is_valid_prefix_key_type(const ObObjTypeClass column_type_class)
{
  return column_type_class == ObStringTC || column_type_class == ObTextTC;
}

int ObDDLResolver::check_prefix_key(const int32_t prefix_len, const ObColumnSchemaV2& column_schema)
{
  int ret = OB_SUCCESS;
  if (prefix_len > 0) {
    if (!is_valid_prefix_key_type(column_schema.get_data_type_class())) {
      ret = OB_WRONG_SUB_KEY;

      SQL_RESV_LOG(
          WARN, "The used key part isn't a string", "data_type_class", column_schema.get_data_type_class(), K(ret));
    } else if (column_schema.get_data_length() < prefix_len) {
      ret = OB_WRONG_SUB_KEY;
      LOG_USER_ERROR(OB_WRONG_SUB_KEY);
      SQL_RESV_LOG(WARN, "The used length is longer than the key part", K(prefix_len), K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::check_string_column_length(const ObColumnSchemaV2& column, const bool is_oracle_mode)
{
  int ret = OB_SUCCESS;
  if (ObStringTC != column.get_data_type_class() || CHARSET_INVALID == column.get_charset_type() ||
      CS_TYPE_INVALID == column.get_collation_type()) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "column infomation is error", K(column), K(ret));
  } else if (ObCharType == column.get_data_type() || ObNCharType == column.get_data_type()) {
    /* compatiable with mysql
     * char & binary : 255 charaters at most
     * varchar & varbinary : 65536 bytes at most
     * varchar(N)&varbinary(N): N is character count, N's upper bound is defined by its charset.
     * char(N)&binary(N): N is charactor count, upper limit is 255 characters.
     * oralce
     * char(N)&raw(N): N is byte count, upper limit is 2000 bytes
     */
    const int64_t max_char_length = is_oracle_mode ? OB_MAX_ORACLE_CHAR_LENGTH_BYTE : OB_MAX_CHAR_LENGTH;
    const int64_t data_len = column.get_data_length();
    if (data_len < 0 || data_len > max_char_length) {
      ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
      LOG_WARN(
          "column data length is invalid", K(ret), K(max_char_length), "real_data_length", column.get_data_length());
      LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH, column.get_column_name(), static_cast<int>(max_char_length));
    } else if (is_oracle_mode && 0 == data_len) {
      ret = OB_ERR_ZERO_LEN_COL;
      LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
    }
  } else if (ObVarcharType == column.get_data_type() || ObNVarchar2Type == column.get_data_type()) {
    int64_t mbmaxlen = 0;
    if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(column.get_collation_type(), mbmaxlen))) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "fail to get mbmaxlen", K(ret), K(column.get_collation_type()));
    } else {
      const int64_t data_len = column.get_data_length();
      if (0 == mbmaxlen) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(ERROR, "mbmaxlen can not be 0", K(ret));
      } else if (data_len < 0 || (is_oracle_mode ? data_len > OB_MAX_ORACLE_VARCHAR_LENGTH
                                                 : data_len * mbmaxlen > OB_MAX_VARCHAR_LENGTH)) {
        ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
        const uint64_t real_data_length = static_cast<uint64_t>(data_len);
        LOG_WARN("column data length is invalid", K(ret), K(data_len), K(real_data_length), K(mbmaxlen));
        LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH,
            column.get_column_name(),
            static_cast<int>(is_oracle_mode ? OB_MAX_ORACLE_VARCHAR_LENGTH : OB_MAX_VARCHAR_LENGTH / mbmaxlen));
      } else if (is_oracle_mode && 0 == data_len) {
        ret = OB_ERR_ZERO_LEN_COL;
        LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
      }
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
  }
  return ret;
}

// raw(N): N byte: upper bound: 2000 byte
int ObDDLResolver::check_raw_column_length(const share::schema::ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;

  if (ObRawType != column.get_data_type()) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "column infomation is error", K(column), K(ret));
  } else {
    const int64_t data_len = column.get_data_length();
    if (data_len < 0 || data_len > OB_MAX_ORACLE_RAW_SQL_COL_LENGTH) {
      ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
      LOG_WARN("column data length is invalid",
          K(ret),
          K(OB_MAX_ORACLE_RAW_SQL_COL_LENGTH),
          "real_data_length",
          column.get_data_length());
      LOG_USER_ERROR(
          OB_ERR_TOO_LONG_COLUMN_LENGTH, column.get_column_name(), static_cast<int>(OB_MAX_ORACLE_RAW_SQL_COL_LENGTH));
    } else if (0 == data_len) {
      ret = OB_ERR_ZERO_LEN_COL;
      LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
    }
  }

  return ret;
}

int ObDDLResolver::check_urowid_column_length(const share::schema::ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  if (ObURowIDType != column.get_data_type()) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "column information is error", K(ret), K(column));
  } else {
    const int64_t data_len = column.get_data_length();
    if (data_len < 0 || data_len > OB_MAX_USER_ROW_KEY_LENGTH) {
      // create table t (a urwoid(int_num));
      // int_num is urowid's decoded max length. i.e primary key's max length
      ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
      LOG_WARN("column data length is invalid",
          K(ret),
          K(OB_MAX_USER_ROW_KEY_LENGTH),
          "real_data_length",
          column.get_data_length());
      LOG_USER_ERROR(
          OB_ERR_TOO_LONG_COLUMN_LENGTH, column.get_column_name(), static_cast<int>(OB_MAX_USER_ROW_KEY_LENGTH));
    } else if (0 == data_len) {
      ret = OB_ERR_ZERO_LEN_COL;
      LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
    }
  }
  return ret;
}

int ObDDLResolver::check_text_length(
    ObCharsetType cs_type, ObCollationType co_type, const char* name, ObObjType& type, int32_t& length)
{
  int ret = OB_SUCCESS;
  int64_t mbmaxlen = 0;
  int32_t default_length = ObAccuracy::DDL_DEFAULT_ACCURACY[type].get_length();
  if (!ob_is_text_tc(type) || CHARSET_INVALID == cs_type || CS_TYPE_INVALID == co_type) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "column infomation is error", K(cs_type), K(co_type), K(ret));
  } else if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(co_type, mbmaxlen))) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "fail to get mbmaxlen", K(ret), K(co_type));
  } else if (0 == mbmaxlen) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(ERROR, "mbmaxlen can not be 0", K(ret), K(co_type), K(mbmaxlen));
  } else if (length < 0) {
    length = default_length;
  } else {
    // eg. text(128) will be tinytext in mysql, and text(65537) will be mediumtext
    if (ObTextType == type) {
      if (length * mbmaxlen > ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length()) {
        ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
        LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH,
            name,
            static_cast<int>(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length() / mbmaxlen));
        SQL_RESV_LOG(WARN,
            "fail to check column data length",
            K(ret),
            K(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length()),
            K(mbmaxlen));
      } else {
        for (int64_t i = ObTinyTextType; i <= ObLongTextType; ++i) {
          default_length = ObAccuracy::DDL_DEFAULT_ACCURACY[i].get_length();
          if (length * mbmaxlen <= default_length) {
            type = static_cast<ObObjType>(i);
            length = default_length;
            break;
          }
        }
      }
    } else if (share::is_mysql_mode() && length * mbmaxlen > default_length) {
      ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
      LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH, name, static_cast<int>(default_length / mbmaxlen));
      SQL_RESV_LOG(WARN, "fail to check column data length", K(ret), K(default_length), K(length), K(mbmaxlen));
    } else {
      length = default_length;
    }
  }
  return ret;
}

// TODO texttc should care about the the defined length not the actual length
int ObDDLResolver::check_text_column_length_and_promote(ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  ObObjType type = column.get_data_type();
  int32_t length = column.get_data_length();
  if (OB_FAIL(check_text_length(
          column.get_charset_type(), column.get_collation_type(), column.get_column_name(), type, length))) {
    LOG_WARN("failed to check text length", K(ret), K(column));
  } else {
    column.set_data_type(type);
    column.set_data_length(length);
  }
  return ret;
}

int ObDDLResolver::check_and_fill_column_charset_info(
    ObColumnSchemaV2& column, const ObCharsetType table_charset_type, const ObCollationType table_collation_type)
{
  int ret = OB_SUCCESS;
  ObCharsetType charset_type = CHARSET_INVALID;
  ObCollationType collation_type = CS_TYPE_INVALID;
  ;
  if (CHARSET_INVALID == table_charset_type || CS_TYPE_INVALID == table_collation_type) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "invalid column charset info!", K(ret));
  } else {
    charset_type = column.get_charset_type();
    collation_type = column.get_collation_type();
  }
  if (OB_FAIL(ret)) {
    // empty
  } else if (column.is_binary_collation() && CS_TYPE_INVALID == collation_type) {
    if (CHARSET_INVALID == charset_type) {
      column.set_charset_type(table_charset_type);
      column.set_collation_type(ObCharset::get_bin_collation(table_charset_type));
    } else {
      column.set_charset_type(charset_type);
      column.set_collation_type(ObCharset::get_bin_collation(charset_type));
    }
  } else if (CHARSET_INVALID == charset_type && CS_TYPE_INVALID == collation_type) {
    column.set_charset_type(table_charset_type);
    column.set_collation_type(table_collation_type);
  } else if (OB_FAIL(ObCharset::check_and_fill_info(charset_type, collation_type))) {
    SQL_RESV_LOG(WARN, "fail to fill charset and collation info", K(collation_type), K(ret));
  } else {
    column.set_charset_type(charset_type);
    column.set_collation_type(collation_type);
  }
  return ret;
}

int ObDDLResolver::resolve_part_func(ObResolverParams& params, const ParseNode* node,
    const ObPartitionFuncType partition_func_type, const ObTableSchema& table_schema,
    ObIArray<ObRawExpr*>& part_func_exprs, ObIArray<ObString>& partition_keys)
{
  int ret = OB_SUCCESS;
  part_func_exprs.reset();
  partition_keys.reset();

  if (OB_ISNULL(node)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("NULL ptr", K(ret));
  } else if (T_EXPR_LIST == node->type_) {
    if (node->num_child_ < 1) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("Partition fun node should not less than 1", K(ret));
    } else if (node->num_child_ > OB_MAX_PART_COLUMNS) {
      ret = OB_ERR_TOO_MANY_PARTITION_FUNC_FIELDS;
      LOG_WARN("Too may partition func fields", K(ret));
    } else {
      ObRawExpr* func_expr = NULL;
      for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) {
        func_expr = NULL;
        if (OB_ISNULL(node->children_[i]) || T_EXPR_LIST == node->children_[i]->type_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("node is null or node type error", K(ret));
        } else if (OB_FAIL(ObResolverUtils::resolve_partition_expr(
                       params, *(node->children_[i]), table_schema, partition_func_type, func_expr, &partition_keys))) {
          LOG_WARN("resolve partition expr failed", K(ret));
        } else if (OB_FAIL(part_func_exprs.push_back(func_expr))) {
          LOG_WARN("array push back fail", K(ret));
        } else {
          LOG_DEBUG("succ to resolve_part_func", KPC(func_expr));

        }  // do nothing
      }    // end of for
    }
  } else {
    ObRawExpr* func_expr = NULL;
    if (OB_FAIL(ObResolverUtils::resolve_partition_expr(
            params, *node, table_schema, partition_func_type, func_expr, &partition_keys))) {
      LOG_WARN("resolve partition expr failed", K(ret));
    } else if (OB_FAIL(part_func_exprs.push_back(func_expr))) {
      LOG_WARN("array push back fail", K(ret));
    } else if (partition_keys.count() > OB_MAX_PART_COLUMNS) {
      ret = OB_ERR_TOO_MANY_PARTITION_FUNC_FIELDS;
      LOG_WARN("too may partition func fields", K(ret));
    }
  }
  if (OB_SUCC(ret)) {
    // check duplicate of PARTITION_FUNC_TYPE_RANGE_COLUMNS
    if (OB_SUCC(ret)) {
      if (partition_func_type == PARTITION_FUNC_TYPE_RANGE_COLUMNS) {
        for (int64_t idx = 0; OB_SUCC(ret) && idx < partition_keys.count(); ++idx) {
          const ObString& key_name = partition_keys.at(idx);
          for (int64_t b_idx = 0; OB_SUCC(ret) && b_idx < idx; ++b_idx) {
            if (ObCharset::case_insensitive_equal(key_name, partition_keys.at(b_idx))) {
              ret = OB_ERR_SAME_NAME_PARTITION_FIELD;
              LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION_FIELD, key_name.length(), key_name.ptr());
            }
          }
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_list_partition_elements(const ObDDLStmt* stmt, ParseNode* node, const bool is_subpartition,
    const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObDDLStmt::array_t& list_value_exprs, ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions,
    int64_t max_used_part_id, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node) || OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt_));
  } else if (!is_subpartition && max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ParseNode* partition_expr_list = node;
    ObPartition partition;
    ObSubPartition subpartition;
    int64_t part_id = OB_INVALID_PARTITION_ID;
    bool use_part_id = false;
    bool has_empty_name = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      subpartition.reset();
      partition.reset();
      ParseNode* element_node = partition_expr_list->children_[i];
      if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
                     OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
                 !is_oracle_mode()) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else {
        ObString partition_name;
        if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
          ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
          partition_name.assign_ptr(
              partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
        } else if (is_subpartition) {
          subpartition.set_is_empty_partition_name(true);
          has_empty_name = true;
        } else {
          partition.set_is_empty_partition_name(true);
          has_empty_name = true;
        }
        ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
        if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
          ret = OB_ERR_TOO_LONG_IDENT;
        } else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST or T_DEFAULT",
              K(ret),
              "expr_list_node type",
              expr_list_node->type_);
        } else if (use_part_id) {
          // special case for backup-restore module
          if (OB_ISNULL(element_node->children_[PART_ID_NODE])) {
            ret = OB_INVALID_ARGUMENT;
            LOG_WARN("Should speicify part id for all parts", K(ret));
            LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
          }
        }
        // add list partition elements to table schema
        if (OB_SUCC(ret)) {
          part_id = OB_INVALID_PARTITION_ID;
          if (is_subpartition) {
            subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
            subpartition.set_sub_part_id(i);
            if (OB_FAIL(subpartition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = subpartitions.push_back(subpartition);
            }
          } else if (OB_ISNULL(element_node->children_[PART_ID_NODE])) {
            part_id = max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + i : i;
          } else {
            bool valid = false;
            part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
            if (OB_FAIL(check_partid_valid(stmt, part_id, max_used_part_id, valid))) {
              LOG_WARN("part id not valid", K(ret));
            } else if (!valid) {
              ret = OB_ERR_UNEXPECTED;
              LOG_WARN("part id not valid", K(ret));
            } else if (0 == i) {
              use_part_id = true;
            } else if (!use_part_id) {
              ret = OB_INVALID_ARGUMENT;
              LOG_WARN("Should speicify part id for all parts", K(ret));
              LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
            }
          }
        }

        if (OB_SUCC(ret)) {
          if (part_id < 0) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("partition id is invalid", K(ret), K(part_id));
          } else {
            partition.set_part_id(part_id);
            if (OB_FAIL(partition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = partitions.push_back(partition);
            }
          }
        }
        if (OB_SUCC(ret)) {
          if (OB_FAIL(resolve_list_partition_value_node(
                  *expr_list_node, partition_name, part_type, part_func_exprs, list_value_exprs, in_tablegroup))) {
            LOG_WARN("failed to resolve list partition value node", K(ret));
          }
        }
      }
    }
    if (OB_UNLIKELY(has_empty_name) &&
        (stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
            stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
      if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
        LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_range_partition_elements(const ObDDLStmt* stmt, ParseNode* node, const bool is_subpartition,
    const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObIArray<ObRawExpr*>& range_value_exprs, ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions,
    int64_t max_used_part_id, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt));
  } else if (!is_subpartition && max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ParseNode* partition_expr_list = node;
    ObPartition partition;
    ObSubPartition subpartition;
    bool init_specified = false;
    bool has_empty_name = false;
    // ignore alter_table with part_id
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      subpartition.reset();
      partition.reset();
      ParseNode* element_node = partition_expr_list->children_[i];
      if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
                     OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
                 !is_oracle_mode()) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else {
        ObString partition_name;
        if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
          ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
          partition_name.assign_ptr(
              partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
        } else if (is_subpartition) {
          subpartition.set_is_empty_partition_name(true);
          has_empty_name = true;
        } else {
          partition.set_is_empty_partition_name(true);
          has_empty_name = true;
        }
        ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
        if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
          ret = OB_ERR_TOO_LONG_IDENT;
        } else if (T_EXPR_LIST != expr_list_node->type_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST", K(ret));
        } else if (part_func_exprs.count() != expr_list_node->num_child_) {
          ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
          LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
        } else {
          // add range partition elements to table schema
          if (OB_SUCC(ret)) {
            if (is_subpartition) {
              subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
              subpartition.set_sub_part_id(i);
              if (OB_FAIL(subpartition.set_part_name(partition_name))) {
                LOG_WARN("Failed to set part name", K(ret));
              } else {
                ret = subpartitions.push_back(subpartition);
              }
            } else {
              int64_t part_id = OB_INVALID_ID;
              bool current_spec = false;
              if (OB_ISNULL(element_node->children_[PART_ID_NODE])) {
                // part_id not specified
                part_id = max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + i : i;
                current_spec = false;
              } else {
                // with part_id
                part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
                if (OB_FAIL(check_partid_valid(stmt, part_id, max_used_part_id, current_spec))) {
                  LOG_WARN("part id not valid", K(ret));
                } else if (!current_spec) {
                  ret = OB_ERR_UNEXPECTED;
                  LOG_WARN("part id not valid", K(ret));
                }
              }
              // all with part id, or all without part id.
              // otherwise unsupported
              if (OB_SUCC(ret)) {
                if (0 == i) {
                  init_specified = current_spec;
                } else if (current_spec != init_specified) {
                  ret = OB_INVALID_ARGUMENT;
                  LOG_WARN("Should speicify part id for all parts", K(ret));
                  LOG_USER_ERROR(
                      OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
                }
              }
              if (OB_FAIL(ret)) {
              } else if (part_id < 0) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("invalid part_id", K(ret), K(part_id));
              } else if (OB_FAIL(partition.set_part_name(partition_name))) {
                LOG_WARN("Failed to set part name", K(ret));
              } else {
                partition.set_part_id(part_id);
                ret = partitions.push_back(partition);
              }
            }
          }
          for (int64_t j = 0; OB_SUCC(ret) && j < expr_list_node->num_child_; j++) {
            if (OB_ISNULL(expr_list_node->children_[j])) {
              ret = OB_ERR_UNEXPECTED;
              LOG_WARN("node is null", K(ret));
            } else if (T_MAXVALUE == expr_list_node->children_[j]->type_) {
              ObRawExpr* maxvalue_expr = NULL;
              ObConstRawExpr* c_expr = NULL;
              c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
              if (NULL != c_expr) {
                c_expr = new (c_expr) ObConstRawExpr();
                maxvalue_expr = c_expr;
                maxvalue_expr->set_data_type(common::ObMaxType);
                if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
                  LOG_WARN("array push back fail", K(ret));
                }
              } else {
                ret = OB_ALLOCATE_MEMORY_FAILED;
              }
            } else if (T_NULL == expr_list_node->children_[j]->type_) {
              ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
              LOG_WARN("null value is not allowed in less than", K(ret));
            } else if (T_EXPR_LIST != expr_list_node->children_[j]->type_) {
              ObRawExpr* part_value_expr = NULL;
              ObRawExpr* part_func_expr = NULL;
              if (OB_FAIL(part_func_exprs.at(j, part_func_expr))) {
                LOG_WARN("get part expr failed", K(j), "size", part_func_exprs.count(), K(ret));
              } else if (OB_ISNULL(part_func_expr)) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("part_func_expr is invalid", K(ret));
              } else if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(params_,
                             *(expr_list_node->children_[j]),
                             partition_name,
                             part_type,
                             *part_func_expr,
                             part_value_expr,
                             in_tablegroup))) {
                LOG_WARN("resolve partition expr failed", K(ret));
              } else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
                LOG_WARN("array push back fail", K(ret));
              }
            } else {
              ret = OB_ERR_PARSER_SYNTAX;
              LOG_WARN("syntax error, expect single expr while expr list got", K(ret));
            }
          }
        }
      }
    }
    if (OB_UNLIKELY(has_empty_name) &&
        (stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
            stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
      if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
        LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_partid_valid(
    const ObDDLStmt* stmt, const int64_t part_id, const int64_t max_used_part_id, bool& valid)
{
  int ret = OB_SUCCESS;
  bool is_sync_ddl_user = false;
  if (OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("stmt is null", K(ret));
  } else if (stmt::T_CREATE_TABLE != stmt->get_stmt_type() && stmt::T_CREATE_TABLEGROUP != stmt->get_stmt_type() &&
             stmt::T_CREATE_INDEX != stmt->get_stmt_type()) {
    ret = OB_ERR_PARSE_SQL;
    LOG_WARN(
        "only support create table or tablegroup or index with part_id", K(ret), "stmt_type", stmt->get_stmt_type());
  } else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
    LOG_WARN("Failed to check sync_dll_user", K(ret));
  } else if (!is_sync_ddl_user) {
    ret = OB_ERR_PARSE_SQL;
    LOG_WARN("Only support for sync ddl user to specify part id", K(ret), "user name", session_info_->get_user_name());
  } else if (max_used_part_id < 0) {
    // must specify max_used_part_id
    ret = OB_OP_NOT_ALLOW;
    LOG_WARN("specific part_id without max_used_part_id not allowed", K(max_used_part_id), K(ret));
    LOG_USER_ERROR(OB_OP_NOT_ALLOW, "specify part_id without max_used_part_id");
  } else if (part_id > max_used_part_id) {
    // can't larger than max_used_part_id
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("part_id is bigger than max_used_part_id", K(part_id), K(max_used_part_id), K(ret));
    LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part_id or max_used_part_id");
  } else {
    valid = true;
  }
  return ret;
}

int ObDDLResolver::check_max_used_part_id_valid(
    const share::schema::ObTableSchema& table_schema, int64_t& max_used_part_id)
{
  int ret = OB_SUCCESS;
  int64_t current_max_part_id = -1;
  if (table_schema.is_auto_partitioned_table()) {
  } else if (table_schema.is_range_part() || table_schema.is_list_part()) {
    // get max part id
    ObPartition** part_array = table_schema.get_part_array();
    if (OB_FAIL(GET_PART_ID(part_array, table_schema.get_first_part_num() - 1, current_max_part_id))) {
      LOG_WARN("Failed to get part id", K(table_schema.get_first_part_num() - 1), K(ret));
    }
  } else {
    current_max_part_id = table_schema.get_part_option().get_part_num() - 1;
  }
  if (OB_SUCC(ret)) {
    if (max_used_part_id < 0) {
      max_used_part_id = current_max_part_id;
    } else if (PARTITION_LEVEL_ZERO == table_schema.get_part_level()) {
      ret = OB_NOT_SUPPORTED;
      SQL_RESV_LOG(WARN, "non-partitioned table with max_used_part_id not support", K(ret), K(max_used_part_id));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "non-partitioned table with max_used_part_id");
    } else if (max_used_part_id < current_max_part_id) {
      ret = OB_INVALID_ARGUMENT;
      SQL_RESV_LOG(WARN, "invalid max_used_part_id", K(ret), K(max_used_part_id), K(current_max_part_id));
      LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max_used_part_id");
    } else {
      // use max_used_part_id_
    }
  }
  return ret;
}

int ObDDLResolver::check_partition_name_duplicate(ParseNode* node, bool is_oracle_modle)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null", K(ret));
  } else {
    hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>* partition_name_set = nullptr;
    void* buf = nullptr;
    int64_t partition_num = node->num_child_;
    ParseNode* partition_expr_list = node;
    ParseNode* element_node = NULL;
    if (OB_ISNULL(buf = allocator_->alloc(
                      sizeof(hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>)))) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_WARN("fail to allocate memory", KR(ret));
    } else {
      partition_name_set =
          new (buf) hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>();
    }
    if (OB_FAIL(ret)) {
    } else if (OB_ISNULL(partition_name_set)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("partition name hash set is null", KR(ret));
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      element_node = partition_expr_list->children_[i];
      if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
                     OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
                 !is_oracle_modle) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else {
        ObString partition_name;
        if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
          ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
          partition_name.assign_ptr(
              partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
          ObPartitionNameHashWrapper partition_name_key(partition_name);
          if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
            ret = OB_ERR_SAME_NAME_PARTITION;
            LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION, partition_name.length(), partition_name.ptr());
          } else {
            if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
              LOG_WARN("add partition name to map failed", K(ret), K(ret));
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObDDLResolver::fill_extended_type_info(const ParseNode& str_list_node, ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  ObArray<ObString> type_info_array;
  CK(NULL != session_info_);
  CK(NULL != allocator_);
  if (OB_FAIL(ret)) {
  } else if (OB_FAIL(ObResolverUtils::resolve_extended_type_info(str_list_node, type_info_array))) {
    LOG_WARN("failed to resolve extended type info", K(ret));
  } else {
    // The resolved extended type info's collation is session connection collation,
    // need convert to column collation finally. The converting may be done in RS,
    // but the session connection collation info is lost in RS, so we convert to a
    // intermediate collation (system collation) here. Convert from the intermediate
    // collation to column collation finally in ObResolverUtils::check_extended_type_info().
    ObCollationType src = session_info_->get_local_collation_connection();
    ObCollationType dst = ObCharset::get_system_collation();
    FOREACH_CNT_X(str, type_info_array, OB_SUCC(ret))
    {
      OZ(ObCharset::charset_convert(*allocator_, *str, src, dst, *str));
    }
  }
  OZ(column.set_extended_type_info(type_info_array));
  return ret;
}

int ObDDLResolver::resolve_enum_or_set_column(const ParseNode* type_node, ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(type_node) || OB_UNLIKELY(type_node->num_child_ != 4) || OB_ISNULL(allocator_) ||
      OB_ISNULL(session_info_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("type node is NULL", K(ret), K(type_node), K(session_info_));
  } else if (OB_ISNULL(type_node->children_[3])) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("child is NULL", K(ret));
  } else if (OB_FAIL(fill_extended_type_info(*(type_node->children_[3]), column))) {
    LOG_WARN("fail to fill type info", K(ret), K(column));
  } else if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
  } else if (OB_FAIL(check_and_fill_column_charset_info(column, charset_type_, collation_type_))) {
    LOG_WARN("fail to check and fill column charset info", K(ret), K(column), K(charset_type_), K(collation_type_));
  } else if (OB_FAIL(check_extended_type_info(column, session_info_->get_sql_mode()))) {
    LOG_WARN("fail to fill extended type info", K(ret), K(column), K(session_info_->get_sql_mode()));
  } else if (OB_FAIL(calc_enum_or_set_data_length(column))) {
    LOG_WARN("fail to calc data length", K(ret), K(column));
  }
  return ret;
}

int ObDDLResolver::calc_enum_or_set_data_length(const ObIArray<common::ObString>& type_info,
    const ObCollationType& collation_type, const ObObjType& type, int32_t& length)
{
  int ret = OB_SUCCESS;
  int32_t cur_len = 0;
  if (OB_UNLIKELY(ObEnumType != type && ObSetType != type)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected column type", K(ret));
  } else if (ObEnumType == type) {
    for (int64_t i = 0; OB_SUCC(ret) && i < type_info.count(); ++i) {
      const ObString& type_str = type_info.at(i);
      cur_len = static_cast<int32_t>(ObCharset::strlen_char(collation_type, type_str.ptr(), type_str.length()));
      length = length < cur_len ? cur_len : length;
    }
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < type_info.count(); ++i) {
      const ObString& type_str = type_info.at(i);
      cur_len = static_cast<int32_t>(ObCharset::strlen_char(collation_type, type_str.ptr(), type_str.length()));
      length += cur_len;
    }
    length +=
        (static_cast<int32_t>(type_info.count()) - 1) * ObCharsetUtils::get_const_str(collation_type, ',').length();
  }
  return ret;
}

int ObDDLResolver::calc_enum_or_set_data_length(ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  int32_t length = 0;
  if (OB_FAIL(calc_enum_or_set_data_length(
          column.get_extended_type_info(), column.get_collation_type(), column.get_data_type(), length))) {
    LOG_WARN("failed to calc enum or set data length", K(ret));
  } else {
    column.set_data_length(length);
  }
  return ret;
}

int ObDDLResolver::check_extended_type_info(ObColumnSchemaV2& column, ObSQLMode sql_mode)
{
  return ObResolverUtils::check_extended_type_info(*allocator_,
      column.get_extended_type_info(),
      ObCharset::get_system_collation(),
      column.get_column_name_str(),
      column.get_data_type(),
      column.get_collation_type(),
      sql_mode);
}

int ObDDLResolver::check_duplicates_in_type_infos(const ObColumnSchemaV2& col, ObSQLMode sql_mode, int32_t& dup_cnt)
{
  return ObResolverUtils::check_duplicates_in_type_infos(col.get_extended_type_info(),
      col.get_column_name_str(),
      col.get_data_type(),
      col.get_collation_type(),
      sql_mode,
      dup_cnt);
}

int ObDDLResolver::check_type_info_incremental_change(
    const ObColumnSchemaV2& ori_schema, const ObColumnSchemaV2& new_schema)
{
  int ret = OB_SUCCESS;
  const ObIArray<common::ObString>& ori_type_info = ori_schema.get_extended_type_info();
  const ObIArray<common::ObString>& new_type_info = new_schema.get_extended_type_info();
  if (OB_UNLIKELY(new_type_info.count() < ori_type_info.count())) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("not support", K(new_type_info.count()), K(ori_type_info.count()), K(ret));
  } else if (OB_UNLIKELY(ori_schema.get_charset_type() != new_schema.get_charset_type())) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("not support", K(ori_schema.get_collation_type()), K(ori_schema.get_collation_type()), K(ret));
  }

  ObCollationType coll_type = ori_schema.get_collation_type();
  for (int64_t i = 0; OB_SUCC(ret) && i < ori_type_info.count(); ++i) {
    const ObString& ori_str = ori_type_info.at(i);
    const ObString& new_str = new_type_info.at(i);
    if (0 != ObCharset::strcmp(coll_type, ori_str.ptr(), ori_str.length(), new_str.ptr(), new_str.length())) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("not support", K(coll_type), K(ori_str), K(new_str), K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::cast_enum_or_set_default_value(const ObColumnSchemaV2& column, ObCastCtx& cast_ctx, ObObj& def_val)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(!def_val.is_string_type())) {
    ret = OB_INVALID_DEFAULT;
    LOG_WARN("invalid default value type", K(def_val), K(ret));
    LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
  } else if (OB_UNLIKELY(!ob_is_enumset_tc(column.get_data_type()))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected column type", K(column), K(ret));
  } else {
    ObExpectType expect_type;
    expect_type.set_type(column.get_data_type());
    expect_type.set_collation_type(column.get_collation_type());
    expect_type.set_type_infos(&column.get_extended_type_info());
    if (OB_FAIL(ObObjCaster::to_type(expect_type, cast_ctx, def_val, def_val))) {
      ret = OB_INVALID_DEFAULT;
      LOG_WARN("fail to cast to enum or set", K(def_val), K(expect_type), K(ret));
      LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
    }
  }

  return ret;
}

int ObDDLResolver::print_expr_to_default_value(
    ObRawExpr& expr, share::schema::ObColumnSchemaV2& column, const ObTimeZoneInfo* tz_info)
{
  int ret = OB_SUCCESS;
  HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf)
  {
    MEMSET(expr_str_buf, 0, sizeof(expr_str_buf));
    int64_t pos = 0;
    ObString expr_def;
    ObObj default_value;
    ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, tz_info);
    if (OB_FAIL(expr_printer.do_print(&expr, T_NONE_SCOPE, true))) {
      LOG_WARN("print expr definition failed", K(expr), K(ret));
    } else if (FALSE_IT(expr_def.assign_ptr(expr_str_buf, static_cast<int32_t>(pos)))) {
    } else if (FALSE_IT(default_value.set_varchar(expr_def))) {
    } else if (FALSE_IT(default_value.set_collation_type(ObCharset::get_system_collation()))) {
    } else if (OB_FAIL(column.set_cur_default_value(default_value))) {
      LOG_WARN("set orig default value failed", K(ret));
    } else {
      LOG_DEBUG("succ to print_expr_to_default_value", K(expr), K(column), K(default_value), K(expr_def), K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::check_default_value(ObObj& default_value, const common::ObTimeZoneInfoWrap& tz_info_wrap,
    const common::ObString* nls_formats, ObIAllocator& allocator, ObTableSchema& table_schema, ObColumnSchemaV2& column)
{
  int ret = OB_SUCCESS;
  const ObObj input_default_value = default_value;
  if (column.is_generated_column()) {
    ObString expr_str;
    ObResolverParams params;
    ObRawExpr* expr = NULL;
    ObRawExprFactory expr_factory(allocator);
    ObSQLSessionInfo empty_session;
    params.expr_factory_ = &expr_factory;
    params.allocator_ = &allocator;
    params.session_info_ = &empty_session;
    if (OB_FAIL(empty_session.test_init(0, 0, 0, &allocator))) {
      LOG_WARN("init empty session failed", K(ret));
    } else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
      LOG_WARN("session load default system variable failed", K(ret));
    } else if (OB_FAIL(input_default_value.get_string(expr_str))) {
      LOG_WARN("get expr string from default value failed", K(ret), K(input_default_value));
    } else if (OB_FAIL(ObResolverUtils::resolve_generated_column_expr(params, expr_str, table_schema, column, expr))) {
      LOG_WARN("resolve generated column expr failed", K(ret));
    } else if (column.get_meta_type().is_null()) {
      column.set_data_type(expr->get_data_type());
      column.set_collation_type(expr->get_collation_type());
      column.set_accuracy(expr->get_accuracy());
    }
  } else if (column.is_default_expr_v2_column()) {
    ObString expr_str;
    ObResolverParams params;
    ObRawExpr* expr = NULL;
    ObRawExprFactory expr_factory(allocator);
    ObSQLSessionInfo empty_session;
    ParamStore empty_param_list((ObWrapperAllocator(allocator)));
    params.expr_factory_ = &expr_factory;
    params.allocator_ = &allocator;
    params.session_info_ = &empty_session;
    params.param_list_ = &empty_param_list;
    common::ObObj tmp_default_value;
    common::ObObj tmp_dest_obj;
    const ObObj* tmp_res_obj = NULL;
    common::ObObj tmp_dest_obj_null;
    const bool is_strict = true;  // oracle mode
    const ObObjType data_type = column.get_data_type();
    const ObAccuracy& accuracy = column.get_accuracy();
    const ObCollationType collation_type = column.get_collation_type();
    const ObDataTypeCastParams dtc_params(
        tz_info_wrap.get_time_zone_info(), nls_formats, CS_TYPE_INVALID, CS_TYPE_INVALID, CS_TYPE_UTF8MB4_GENERAL_CI);
    ObCastCtx cast_ctx(&allocator, &dtc_params, CM_NONE, column.get_collation_type());
    if (OB_FAIL(empty_session.test_init(0, 0, 0, &allocator))) {
      LOG_WARN("init empty session failed", K(ret));
    } else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
      LOG_WARN("session load default system variable failed", K(ret));
    } else if (OB_FAIL(empty_session.set_tz_info_wrap(tz_info_wrap))) {
      LOG_WARN("fail to set set_tz_info_wrap", K(ret));
    } else if (FALSE_IT(empty_session.set_nls_formats(nls_formats))) {
    } else if (FALSE_IT(empty_session.set_compatibility_mode(
                   share::is_oracle_mode() ? ObCompatibilityMode::ORACLE_MODE : ObCompatibilityMode::MYSQL_MODE))) {
    } else if (FALSE_IT(
                   empty_session.set_sql_mode(share::is_oracle_mode() ? DEFAULT_ORACLE_MODE : DEFAULT_MYSQL_MODE))) {
    } else if (OB_FAIL(input_default_value.get_string(expr_str))) {
      LOG_WARN("get expr string from default value failed", K(ret), K(input_default_value));
    } else if (OB_FAIL(ObResolverUtils::resolve_default_expr_v2_column_expr(params, expr_str, column, expr))) {
      LOG_WARN("resolve expr_default expr failed", K(expr_str), K(column), K(ret));
    } else if (OB_FAIL(ObSQLUtils::calc_simple_expr_without_row(stmt::StmtType::T_NONE,
                   params.session_info_,
                   expr,
                   tmp_default_value,
                   params.param_list_,
                   allocator))) {
      LOG_WARN("Failed to get simple expr value", K(ret));
    } else if (OB_FAIL(ObObjCaster::to_type(data_type, cast_ctx, tmp_default_value, tmp_dest_obj, tmp_res_obj))) {
      LOG_WARN("cast obj failed, ",
          "src type",
          tmp_default_value.get_type(),
          "dest type",
          data_type,
          K(tmp_default_value),
          K(ret));
    } else if (OB_ISNULL(tmp_res_obj)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("cast obj failed, ",
          "src type",
          tmp_default_value.get_type(),
          "dest type",
          data_type,
          K(tmp_default_value),
          K(ret));
    } else if (OB_FAIL(obj_collation_check(is_strict, collation_type, *const_cast<ObObj*>(tmp_res_obj)))) {
      LOG_WARN("failed to check collation", K(ret), K(collation_type), K(tmp_dest_obj));
    } else if (OB_FAIL(
                   obj_accuracy_check(cast_ctx, accuracy, collation_type, *tmp_res_obj, tmp_dest_obj, tmp_res_obj))) {
      LOG_WARN("failed to check accuracy", K(ret), K(accuracy), K(collation_type), KPC(tmp_res_obj));
    } else if (0 == input_default_value.get_string().compare("''")) {
      // if default is '', we should store '' instead of NULL.
      // FIXME::when observer differentiate '' and null, we can delete this code
      tmp_dest_obj_null.set_varchar(input_default_value.get_string());
      tmp_dest_obj_null.set_collation_type(ObCharset::get_system_collation());
      if (OB_FAIL(column.set_cur_default_value(tmp_dest_obj_null))) {
        LOG_WARN("set orig default value failed", K(ret));
      }
    } else if (OB_FAIL(print_expr_to_default_value(*expr, column, tz_info_wrap.get_time_zone_info()))) {
      LOG_WARN("fail to print_expr_to_default_value", KPC(expr), K(column), K(ret));
    }
    LOG_DEBUG("finish check default value",
        K(input_default_value),
        K(expr_str),
        K(tmp_default_value),
        K(tmp_dest_obj),
        K(tmp_dest_obj_null),
        KPC(expr),
        K(ret));
  } else {
    if (OB_FAIL(cast_default_value(default_value, tz_info_wrap.get_time_zone_info(), nls_formats, allocator, column))) {
      LOG_WARN(
          "fail to cast default value!", K(default_value), KPC(tz_info_wrap.get_time_zone_info()), K(column), K(ret));
    } else if (OB_FAIL(check_default_value_length(default_value, column))) {
      LOG_WARN("fail to check default value length", K(default_value), K(column), K(ret));
    } else {
      default_value.set_collation_type(column.get_collation_type());
      LOG_DEBUG("succ to set default value", K(input_default_value), K(default_value), K(column), K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::calc_default_value(share::schema::ObColumnSchemaV2& column, common::ObObj& default_value,
    const common::ObTimeZoneInfoWrap& tz_info_wrap, const common::ObString* nls_formats,
    common::ObIAllocator& allocator)
{
  int ret = OB_SUCCESS;
  if (IS_DEFAULT_NOW_OBJ(default_value)) {
    int64_t cur_time = ObTimeUtility::current_time();
    ObTimeConverter::round_datetime(column.get_data_scale(), cur_time);
    switch (column.get_data_type()) {
      case ObDateTimeType: {
        int64_t dt_value = 0;
        if (OB_FAIL(ObTimeConverter::timestamp_to_datetime(cur_time, tz_info_wrap.get_time_zone_info(), dt_value))) {
          LOG_WARN("failed to convert timestamp to datetime", K(ret));
        } else {
          ObTimeConverter::round_datetime(column.get_data_scale(), dt_value);
          default_value.set_datetime(dt_value);
        }
        break;
      }
      case ObTimestampType: {
        ObTimeConverter::round_datetime(column.get_data_scale(), cur_time);
        default_value.set_timestamp(cur_time);
        break;
      }
      default: {
        ret = OB_NOT_SUPPORTED;
        LOG_WARN("UnKnown type!", "default value type", column.get_data_type(), K(ret));
        break;
      }
    }
  } else if (column.is_default_expr_v2_column()) {
    ObString expr_str;
    ObResolverParams params;
    ObRawExpr* expr = NULL;
    ObRawExprFactory expr_factory(allocator);
    ObSQLSessionInfo empty_session;
    ParamStore empty_param_list((ObWrapperAllocator(allocator)));
    params.expr_factory_ = &expr_factory;
    params.allocator_ = &allocator;
    params.session_info_ = &empty_session;
    params.param_list_ = &empty_param_list;
    if (OB_FAIL(empty_session.test_init(0, 0, 0, &allocator))) {
      LOG_WARN("init empty session failed", K(ret));
    } else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
      LOG_WARN("session load default system variable failed", K(ret));
    } else if (OB_FAIL(empty_session.set_tz_info_wrap(tz_info_wrap))) {
      LOG_WARN("fail to set set_tz_info_wrap", K(ret));
    } else if (FALSE_IT(empty_session.set_nls_formats(nls_formats))) {
    } else if (FALSE_IT(empty_session.set_compatibility_mode(
                   share::is_oracle_mode() ? ObCompatibilityMode::ORACLE_MODE : ObCompatibilityMode::MYSQL_MODE))) {
    } else if (FALSE_IT(
                   empty_session.set_sql_mode(share::is_oracle_mode() ? DEFAULT_ORACLE_MODE : DEFAULT_MYSQL_MODE))) {
    } else if (OB_FAIL(default_value.get_string(expr_str))) {
      LOG_WARN("get expr string from default value failed", K(ret), K(default_value));
    } else if (OB_FAIL(ObResolverUtils::resolve_default_expr_v2_column_expr(params, expr_str, column, expr))) {
      LOG_WARN("resolve expr_default expr failed", K(ret));
    } else if (OB_FAIL(ObSQLUtils::calc_simple_expr_without_row(
                   stmt::StmtType::T_NONE, params.session_info_, expr, default_value, params.param_list_, allocator))) {
      LOG_WARN("Failed to get simple expr value", K(ret));
    } else {
      ObObj dest_obj;
      const ObDataTypeCastParams dtc_params(
          tz_info_wrap.get_time_zone_info(), nls_formats, CS_TYPE_INVALID, CS_TYPE_INVALID, CS_TYPE_UTF8MB4_GENERAL_CI);
      ObCastCtx cast_ctx(&allocator, &dtc_params, CM_NONE, column.get_collation_type());
      if (OB_FAIL(ObObjCaster::to_type(column.get_data_type(), cast_ctx, default_value, dest_obj))) {
        LOG_WARN("cast obj failed, ",
            "src type",
            default_value.get_type(),
            "dest type",
            column.get_data_type(),
            K(default_value),
            K(ret));
      } else {
        dest_obj.set_scale(column.get_data_scale());
        default_value = dest_obj;
      }
    }
    LOG_DEBUG("finish calc default value", K(column), K(expr_str), K(default_value), KPC(expr), K(ret));
  } else {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("it should not arrive here", K(ret), K(default_value), K(column), K(lbt()));
  }
  return ret;
}

int ObDDLResolver::resolve_range_partition_elements(ParseNode* node, const bool is_subpartition,
    const ObPartitionFuncType part_type, const int64_t expr_num, ObIArray<ObRawExpr*>& range_value_exprs,
    ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node) || OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), KP(stmt_));
  } else if (expr_num <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("expr num is invalid", K(ret), K(expr_num));
  } else {
    int64_t partition_num = node->num_child_;
    ParseNode* partition_expr_list = node;
    ObPartition partition;
    ObSubPartition subpartition;
    bool use_part_id = false;
    const ObCreateTablegroupStmt* tablegroup_stmt = static_cast<ObCreateTablegroupStmt*>(stmt_);
    bool has_empty_name = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      subpartition.reset();
      partition.reset();
      ParseNode* element_node = partition_expr_list->children_[i];
      if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
                     OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
                 !is_oracle_mode()) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else {
        ObString partition_name;
        if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
          ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
          partition_name.assign_ptr(
              partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
        } else if (is_subpartition) {
          subpartition.set_is_empty_partition_name(true);
          has_empty_name = true;
        } else {
          partition.set_is_empty_partition_name(true);
          has_empty_name = true;
        }
        ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
        if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
          ret = OB_ERR_TOO_LONG_IDENT;
        } else if (T_EXPR_LIST != expr_list_node->type_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST", K(ret));
        } else if (expr_num != expr_list_node->num_child_) {
          ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
          LOG_WARN("Inconsistency in usage of column lists for partitioning near",
              K(ret),
              K(expr_num),
              "num_child",
              expr_list_node->num_child_);
        } else if ((is_subpartition) && OB_NOT_NULL(element_node->children_[PART_ID_NODE])) {
          ret = OB_ERR_PARSE_SQL;
          LOG_WARN("not support subpartition with part_id", K(ret), K(is_subpartition), K(in_tablegroup));
        } else if (use_part_id && OB_ISNULL(element_node->children_[PART_ID_NODE])) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
        } else {
          if (is_subpartition) {
            subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
            subpartition.set_sub_part_id(i);
            if (OB_FAIL(subpartition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = subpartitions.push_back(subpartition);
            }
          } else {
            if (nullptr == element_node->children_[PART_ID_NODE]) {
              partition.set_part_id(i);
            } else if (OB_ISNULL(tablegroup_stmt) || OB_ISNULL(element_node->children_[PART_ID_NODE]->children_[0])) {
              ret = OB_ERR_UNEXPECTED;
              LOG_WARN("not create tablegroup stmt or part id node is null", K(ret), "stmt", *stmt_);
            } else {
              bool valid = false;
              const int64_t max_used_part_id = tablegroup_stmt->get_max_used_part_id();
              const int64_t part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
              partition.set_part_id(part_id);
              if (OB_FAIL(check_partid_valid(tablegroup_stmt, part_id, max_used_part_id, valid))) {
                LOG_WARN("part id not valid", K(ret));
              } else if (!valid) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("part id not valid", K(ret));
              } else if (0 == i) {
                use_part_id = true;
              } else if (!use_part_id) {
                ret = OB_INVALID_ARGUMENT;
                LOG_WARN("Should speicify part id for all parts", K(ret));
                LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
              }
            }
            if (OB_FAIL(ret)) {
            } else if (OB_FAIL(partition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = partitions.push_back(partition);
            }
          }
          if (OB_FAIL(ret)) {
            // do nothing
          } else if (OB_FAIL(resolve_range_value_exprs(
                         expr_list_node, part_type, partition_name, range_value_exprs, in_tablegroup))) {
            LOG_WARN("fail to resolve range partition element", K(ret));
          }
        }
      }
    }
    if (OB_UNLIKELY(has_empty_name) &&
        (stmt::T_CREATE_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt_->get_stmt_type() ||
            stmt::T_CREATE_INDEX == stmt_->get_stmt_type())) {
      if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
        LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_range_partition_elements(ParseNode* node, const bool is_subpartition,
    const ObPartitionFuncType part_type, ObIArray<ObRawExpr*>& range_value_exprs, ObIArray<ObPartition>& partitions,
    ObIArray<ObSubPartition>& subpartitions, int64_t& expr_num, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  expr_num = OB_INVALID_INDEX;
  if (OB_ISNULL(node)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node));
  } else {
    int64_t partition_num = node->num_child_;
    ParseNode* partition_expr_list = node;
    ObPartition partition;
    ObSubPartition subpartition;
    bool has_empty_name = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      subpartition.reset();
      partition.reset();
      ParseNode* element_node = partition_expr_list->children_[i];
      if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
                     OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
                 !is_oracle_mode()) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else {
        ObString partition_name;
        if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
          ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
          partition_name.assign_ptr(
              partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
        } else if (is_subpartition) {
          subpartition.set_is_empty_partition_name(true);
          bool has_empty_name = false;
        } else {
          partition.set_is_empty_partition_name(true);
          bool has_empty_name = false;
        }
        ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
        if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
          ret = OB_ERR_TOO_LONG_IDENT;
        } else if (T_EXPR_LIST != expr_list_node->type_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST", K(ret));
        } else if (OB_INVALID_INDEX != expr_num && expr_num != expr_list_node->num_child_) {
          ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
          LOG_WARN("Inconsistency in usage of column lists for partitioning near",
              K(ret),
              K(expr_num),
              "num_child",
              expr_list_node->num_child_);
        } else if ((in_tablegroup || is_subpartition) && OB_NOT_NULL(element_node->children_[PART_ID_NODE])) {
          ret = OB_ERR_PARSE_SQL;
          LOG_WARN("not support tablegroup or subpartition with part_id", K(ret), K(is_subpartition), K(in_tablegroup));
        } else {
          if (is_subpartition) {
            subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
            subpartition.set_sub_part_id(i);
            if (OB_FAIL(subpartition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = subpartitions.push_back(subpartition);
            }
          } else {
            partition.set_part_id(i);
            if (OB_FAIL(partition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = partitions.push_back(partition);
            }
          }
          if (OB_FAIL(ret)) {
            // do nothing
          } else if (OB_FAIL(resolve_range_value_exprs(
                         expr_list_node, part_type, partition_name, range_value_exprs, in_tablegroup))) {
            LOG_WARN("fail to resolve range partition element", K(ret));
          } else {
            expr_num = expr_list_node->num_child_;
          }
        }
      }
    }
    if (OB_UNLIKELY(has_empty_name) &&
        (stmt::T_CREATE_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt_->get_stmt_type() ||
            stmt::T_CREATE_INDEX == stmt_->get_stmt_type())) {
      if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
        LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_range_value_exprs(ParseNode* expr_list_node, const ObPartitionFuncType part_type,
    const ObString& partition_name, ObIArray<ObRawExpr*>& range_value_exprs, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(expr_list_node)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(expr_list_node));
  } else {
    for (int64_t j = 0; OB_SUCC(ret) && j < expr_list_node->num_child_; j++) {
      if (OB_ISNULL(expr_list_node->children_[j])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("node is null", K(ret));
      } else if (T_MAXVALUE == expr_list_node->children_[j]->type_) {
        ObRawExpr* maxvalue_expr = NULL;
        ObConstRawExpr* c_expr = NULL;
        c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
        if (NULL != c_expr) {
          c_expr = new (c_expr) ObConstRawExpr();
          maxvalue_expr = c_expr;
          maxvalue_expr->set_data_type(common::ObMaxType);
          if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
            LOG_WARN("array push back fail", K(ret));
          }
        } else {
          ret = OB_ALLOCATE_MEMORY_FAILED;
        }
      } else if (T_NULL == expr_list_node->children_[j]->type_) {
        ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
        LOG_WARN("null value is not allowed in less than", K(ret));
      } else if (T_EXPR_LIST != expr_list_node->children_[j]->type_) {
        ObRawExpr* part_value_expr = NULL;
        if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
                params_, *(expr_list_node->children_[j]), partition_name, part_type, part_value_expr, in_tablegroup))) {
          LOG_WARN("resolve partition expr failed", K(ret));
        } else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
          LOG_WARN("array push back fail", K(ret));
        }
      } else {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("expr_node type is error", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_list_partition_elements(ParseNode* node, const bool is_subpartition,
    const ObPartitionFuncType part_type, int64_t& expr_num, ObDDLStmt::array_t& list_value_exprs,
    ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node) || OB_ISNULL(stmt_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt_));
  } else {
    int64_t partition_num = node->num_child_;
    ParseNode* partition_expr_list = node;
    ObPartition partition;
    ObSubPartition subpartition;
    int64_t first_non_default_value_idx = OB_INVALID_INDEX;
    bool use_part_id = false;
    const sql::ObCreateTablegroupStmt* tablegroup_stmt = static_cast<ObCreateTablegroupStmt*>(stmt_);
    bool has_empty_name = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      subpartition.reset();
      partition.reset();
      ParseNode* element_node = partition_expr_list->children_[i];
      if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
                     OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
                 !is_oracle_mode()) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("partition expr list node is null", K(ret), K(element_node));
      } else if (is_subpartition && OB_NOT_NULL(element_node->children_[PART_ID_NODE])) {
        ret = OB_ERR_PARSE_SQL;
        LOG_WARN("subpartition can not specify part id", K(ret), K(i), K(is_subpartition), K(in_tablegroup));
      } else {
        ObString partition_name;
        if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
          ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
          partition_name.assign_ptr(
              partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
        } else if (is_subpartition) {
          subpartition.set_is_empty_partition_name(true);
          has_empty_name = true;
        } else {
          partition.set_is_empty_partition_name(true);
          has_empty_name = true;
        }
        ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
        if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
          ret = OB_ERR_TOO_LONG_IDENT;
        } else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST or T_DEFAULT", K(ret));
        }
        // add list partition elements to tablegroup schema
        if (OB_SUCC(ret)) {
          if (is_subpartition) {
            subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
            subpartition.set_sub_part_id(i);
            if (OB_FAIL(subpartition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = subpartitions.push_back(subpartition);
            }
          } else {
            if (use_part_id && OB_ISNULL(element_node->children_[PART_ID_NODE])) {
              ret = OB_INVALID_ARGUMENT;
              LOG_WARN("Should speicify part id for all parts", K(ret));
              LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
            } else if (nullptr == element_node->children_[PART_ID_NODE]) {
              partition.set_part_id(i);
            } else if (OB_ISNULL(tablegroup_stmt) || OB_ISNULL(element_node->children_[PART_ID_NODE]->children_[0])) {
              ret = OB_ERR_UNEXPECTED;
              LOG_WARN("not create tablegroup stmt or part id node is null", K(ret), "stmt", *stmt_);
            } else {
              bool valid = false;
              const int64_t max_used_part_id = tablegroup_stmt->get_max_used_part_id();
              const int64_t part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
              partition.set_part_id(part_id);
              if (OB_FAIL(check_partid_valid(tablegroup_stmt, part_id, max_used_part_id, valid))) {
                LOG_WARN("part id not valid", K(ret));
              } else if (!valid) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("part id not valid", K(ret));
              } else if (0 == i) {
                use_part_id = true;
              } else if (!use_part_id) {
                ret = OB_INVALID_ARGUMENT;
                LOG_WARN("Should speicify part id for all parts", K(ret));
                LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
              }
            }
            if (OB_FAIL(ret)) {
            } else if (OB_FAIL(partition.set_part_name(partition_name))) {
              LOG_WARN("Failed to set part name", K(ret));
            } else {
              ret = partitions.push_back(partition);
            }
          }
        }
        if (OB_SUCC(ret)) {
          ObOpRawExpr* row_expr = NULL;
          if (OB_ISNULL(params_.expr_factory_)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("get unexpected null", K(ret));
          } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_OP_ROW, row_expr))) {
            LOG_WARN("failed to create raw expr", K(ret));
          } else if (OB_ISNULL(row_expr)) {
            ret = OB_ALLOCATE_MEMORY_FAILED;
            LOG_WARN("failed to allcoate memory", K(ret));
          } else if (T_DEFAULT == expr_list_node->type_) {
            // replace default with max
            ObRawExpr* maxvalue_expr = NULL;
            ObConstRawExpr* c_expr = NULL;
            c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
            if (OB_ISNULL(c_expr)) {
              ret = OB_ALLOCATE_MEMORY_FAILED;
              LOG_WARN("failed to allcoate memory", K(ret));
            } else {
              c_expr = new (c_expr) ObConstRawExpr();
              maxvalue_expr = c_expr;
              maxvalue_expr->set_data_type(common::ObMaxType);
              if (OB_FAIL(row_expr->add_param_expr(maxvalue_expr))) {
                LOG_WARN("failed add param expr", K(ret));
              } else if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
                LOG_WARN("array push back fail", K(ret));
              }
            }
          } else {
            ObSEArray<ObRawExpr*, 16> part_value_exprs;

            bool is_all_expr_list = false;
            expr_num = OB_INVALID_COUNT;
            if (expr_list_node->num_child_ > 0) {
              is_all_expr_list = (expr_list_node->children_[0]->type_ == T_EXPR_LIST);
            }
            for (int64_t j = 0; OB_SUCC(ret) && j < expr_list_node->num_child_; j++) {
              part_value_exprs.reset();
              if (OB_ISNULL(expr_list_node->children_[j])) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("node is null", K(ret));
              } else if ((is_all_expr_list && expr_list_node->children_[j]->type_ != T_EXPR_LIST) ||
                         (!is_all_expr_list && expr_list_node->children_[j]->type_ == T_EXPR_LIST)) {
                ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
                LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
              } else if (OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(params_,
                             *(expr_list_node->children_[j]),
                             partition_name,
                             part_type,
                             expr_num,
                             part_value_exprs,
                             in_tablegroup))) {
                LOG_WARN("resolve partition expr failed", K(ret));
              }
              for (int64_t k = 0; OB_SUCC(ret) && k < part_value_exprs.count(); k++) {
                int64_t idx = row_expr->get_param_count() % expr_num;
                ObObjType cur_data_type = part_value_exprs.at(k)->get_data_type();
                ObObjType pre_data_type = cur_data_type;
                if (first_non_default_value_idx >= 0) {
                  if (list_value_exprs.at(first_non_default_value_idx)->get_param_count() <= idx) {
                    ret = OB_ERR_UNEXPECTED;
                    LOG_WARN("value expr num in row is invalid",
                        K(ret),
                        K(first_non_default_value_idx),
                        K(idx),
                        K(list_value_exprs.at(first_non_default_value_idx)),
                        KPC(part_value_exprs.at(k)));
                  } else {
                    pre_data_type =
                        list_value_exprs.at(first_non_default_value_idx)->get_param_expr(idx)->get_data_type();
                  }
                } else if (row_expr->get_param_count() > idx) {
                  pre_data_type = row_expr->get_param_expr(idx)->get_data_type();
                }
                if (OB_FAIL(ret)) {
                  // do nothing
                } else if (ObMaxType != cur_data_type && ObMaxType != pre_data_type && cur_data_type != pre_data_type) {
                  ret = OB_ERR_WRONG_TYPE_COLUMN_VALUE_ERROR;
                  LOG_USER_ERROR(OB_ERR_WRONG_TYPE_COLUMN_VALUE_ERROR);
                  LOG_WARN("object type is invalid ", K(ret), K(cur_data_type), K(pre_data_type));
                } else if (OB_FAIL(row_expr->add_param_expr(part_value_exprs.at(k)))) {
                  LOG_WARN("array push back fail", K(ret));
                }
              }
            }
            if (OB_SUCC(ret)) {
              if (expr_num > 1 && !is_all_expr_list) {
                if (row_expr->get_param_count() != expr_num) {
                  ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
                  LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret), K(expr_num));
                }
              }
            }
            if (OB_SUCC(ret)) {
              if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
                LOG_WARN("array push back fail", K(ret));
              } else if (first_non_default_value_idx < 0) {
                first_non_default_value_idx = i;
              }
            }
          }
        }
      }
    }
    if (OB_UNLIKELY(has_empty_name) &&
        (stmt::T_CREATE_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt_->get_stmt_type() ||
            stmt::T_CREATE_INDEX == stmt_->get_stmt_type())) {
      if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
        LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_column_in_foreign_key(const ObTableSchema& table_schema, const ObString& column_name)
{
  int ret = OB_SUCCESS;
  if (table_schema.is_parent_table() || table_schema.is_child_table()) {
    const ObColumnSchemaV2* alter_column = table_schema.get_column_schema(column_name);
    if (OB_ISNULL(alter_column)) {
      // do nothing
    } else {
      const ObIArray<ObForeignKeyInfo>& foreign_key_infos = table_schema.get_foreign_key_infos();
      for (int64_t i = 0; OB_SUCC(ret) && i < foreign_key_infos.count(); i++) {
        const ObForeignKeyInfo& foreign_key_info = foreign_key_infos.at(i);
        if (table_schema.get_table_id() == foreign_key_info.parent_table_id_) {
          for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.parent_column_ids_.count(); j++) {
            if (alter_column->get_column_id() == foreign_key_info.parent_column_ids_.at(j)) {
              ret = OB_ERR_ALTER_COLUMN_FK;
              LOG_USER_ERROR(OB_ERR_ALTER_COLUMN_FK, column_name.length(), column_name.ptr());
            }
          }
        }
        if (table_schema.get_table_id() == foreign_key_info.child_table_id_) {
          for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.child_column_ids_.count(); j++) {
            if (alter_column->get_column_id() == foreign_key_info.child_column_ids_.at(j)) {
              ret = OB_ERR_ALTER_COLUMN_FK;
              LOG_USER_ERROR(OB_ERR_ALTER_COLUMN_FK, column_name.length(), column_name.ptr());
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_column_in_check_constraint_for_oracle(
    const share::schema::ObTableSchema& table_schema, const ObString& column_name, ObAlterTableStmt* alter_table_stmt)
{
  int ret = OB_SUCCESS;
  const ObColumnSchemaV2* alter_column = table_schema.get_column_schema(column_name);
  if (OB_ISNULL(alter_column)) {
    // do nothing
  } else {
    for (ObTableSchema::const_constraint_iterator iter = table_schema.constraint_begin();
         OB_SUCC(ret) && (iter != table_schema.constraint_end());
         ++iter) {
      if (CONSTRAINT_TYPE_CHECK == (*iter)->get_constraint_type()) {
        for (ObConstraint::const_cst_col_iterator cst_col_iter = (*iter)->cst_col_begin();
             OB_SUCC(ret) && (cst_col_iter != (*iter)->cst_col_end());
             ++cst_col_iter) {
          if (*cst_col_iter == alter_column->get_column_id()) {
            if (0 == (*iter)->get_column_cnt()) {
              ret = OB_ERR_UNEXPECTED;
              SQL_RESV_LOG(WARN, "check cst don't have column info", K(ret), K(**iter));
            } else if (1 == (*iter)->get_column_cnt()) {
              // drop check constraint cascaded
              AlterTableSchema& alter_table_schema = alter_table_stmt->get_alter_table_arg().alter_table_schema_;
              if (OB_FAIL(alter_table_schema.add_constraint(**iter))) {
                SQL_RESV_LOG(WARN, "add constraint failed!", K(ret), K(**iter));
              } else {
                alter_table_stmt->get_alter_table_arg().alter_constraint_type_ = ObAlterTableArg::DROP_CONSTRAINT;
              }
            } else {
              // if check constraint includes more than one column, throw
              ret = OB_ERR_DROP_COL_REFERENCED_MULTI_COLS_CONSTRAINT;
              SQL_RESV_LOG(WARN,
                  "column is referenced in a multi-column constraint",
                  K(ret),
                  K(alter_column->get_column_name_str()),
                  K((*iter)->get_constraint_name_str()),
                  K((*iter)->get_check_expr_str()));
            }
          }
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::check_column_in_foreign_key_for_oracle(
    const ObTableSchema& table_schema, const ObString& column_name, ObAlterTableStmt* alter_table_stmt)
{
  int ret = OB_SUCCESS;
  if (table_schema.is_parent_table() || table_schema.is_child_table()) {
    const ObColumnSchemaV2* alter_column = table_schema.get_column_schema(column_name);
    if (OB_ISNULL(alter_column)) {
      // do full check in RS
    } else {
      const ObIArray<ObForeignKeyInfo>& foreign_key_infos = table_schema.get_foreign_key_infos();
      for (int64_t i = 0; OB_SUCC(ret) && i < foreign_key_infos.count(); i++) {
        const ObForeignKeyInfo& foreign_key_info = foreign_key_infos.at(i);
        // column in parent table can't be deleted
        if (OB_SUCC(ret) && table_schema.get_table_id() == foreign_key_info.parent_table_id_) {
          for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.parent_column_ids_.count(); j++) {
            if (alter_column->get_column_id() == foreign_key_info.parent_column_ids_.at(j)) {
              ret = OB_ERR_DROP_PARENT_KEY_COLUMN;
            }
          }
        }
        if (OB_SUCC(ret) && table_schema.get_table_id() == foreign_key_info.child_table_id_ &&
            foreign_key_info.child_column_ids_.count() > 1) {
          for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.child_column_ids_.count(); j++) {
            if (alter_column->get_column_id() == foreign_key_info.child_column_ids_.at(j)) {
              ret = OB_ERR_MODIFY_OR_DROP_MULTI_COLUMN_CONSTRAINT;
            }
          }
        }
        if (OB_SUCC(ret) && table_schema.get_table_id() == foreign_key_info.child_table_id_ &&
            foreign_key_info.child_column_ids_.count() == 1) {
          if (alter_column->get_column_id() == foreign_key_info.child_column_ids_.at(0)) {
            ObDropForeignKeyArg* foreign_key_arg = NULL;
            void* tmp_ptr = NULL;
            if (OB_ISNULL(tmp_ptr = allocator_->alloc(sizeof(ObDropForeignKeyArg)))) {
              ret = OB_ALLOCATE_MEMORY_FAILED;
              SQL_RESV_LOG(ERROR, "failed to allocate memory", K(ret));
            } else if (FALSE_IT(foreign_key_arg = new (tmp_ptr) ObDropForeignKeyArg())) {
            } else if (FALSE_IT(foreign_key_arg->foreign_key_name_.assign_ptr(
                           foreign_key_info.foreign_key_name_.ptr(), foreign_key_info.foreign_key_name_.length()))) {
            } else if (OB_ISNULL(alter_table_stmt)) {
              ret = OB_ERR_UNEXPECTED;
              SQL_RESV_LOG(WARN, "alter table stmt should not be null", K(ret));
            } else if (OB_FAIL(alter_table_stmt->add_index_arg(foreign_key_arg))) {
              SQL_RESV_LOG(WARN, "add index to drop_index_list failed!", K(ret));
            } else {
              alter_table_stmt->set_alter_table_index();
            }
          }
        }
      }
    }
  }
  return ret;
}

bool ObDDLResolver::is_ids_match(const ObIArray<uint64_t>& src_list, const ObIArray<uint64_t>& dest_list)
{
  bool is_match = true;
  ObSEArray<uint64_t, 8> tmp_src_list;
  ObSEArray<uint64_t, 8> tmp_dest_list;
  if (src_list.count() != dest_list.count()) {
    is_match = false;
  } else {
    for (int64_t i = 0; i < src_list.count(); ++i) {
      tmp_src_list.push_back(src_list.at(i));
      tmp_dest_list.push_back(dest_list.at(i));
    }
    std::sort(tmp_src_list.begin(), tmp_src_list.end());
    std::sort(tmp_dest_list.begin(), tmp_dest_list.end());
    for (int64_t i = 0; is_match && i < tmp_src_list.count(); ++i) {
      if (tmp_src_list.at(i) != tmp_dest_list.at(i)) {
        is_match = false;
      }
    }
  }
  return is_match;
}

int ObDDLResolver::check_index_columns_equal_foreign_key(
    const ObTableSchema& table_schema, const ObTableSchema& index_table_schema)
{
  int ret = OB_SUCCESS;
  if (table_schema.is_child_table()) {
    ObString index_name;
    ObSEArray<uint64_t, 8> index_column_ids;
    const ObIndexInfo& index_info = index_table_schema.get_index_info();
    if (OB_FAIL(index_info.get_column_ids(index_column_ids))) {
      LOG_WARN("failed to get column ids from ObRowkeyInfo", K(ret));
    } else if (OB_FAIL(index_table_schema.get_index_name(index_name))) {
      LOG_WARN("failed to get index name", K(ret));
    }
    const ObIArray<ObForeignKeyInfo>& foreign_key_infos = table_schema.get_foreign_key_infos();
    for (int64_t i = 0; OB_SUCC(ret) && i < foreign_key_infos.count(); ++i) {
      const ObForeignKeyInfo& foreign_key_info = foreign_key_infos.at(i);
      const int64_t child_column_num = foreign_key_info.child_column_ids_.count();
      const uint64_t data_table_id = index_table_schema.get_data_table_id();
      if (0 == child_column_num) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("expected foreign key columns num", K(ret), K(child_column_num));
      }
      if (OB_SUCC(ret)) {
        if (data_table_id == foreign_key_info.child_table_id_) {
          if (child_column_num == index_table_schema.get_index_column_number()) {
            if (is_ids_match(index_column_ids, foreign_key_info.child_column_ids_)) {
              ret = OB_ERR_ALTER_COLUMN_FK;
              LOG_USER_ERROR(OB_ERR_ALTER_COLUMN_FK, index_name.length(), index_name.ptr());
            }
          }
        }  // child_table_id_
      }
    }  // for
  }
  return ret;
}

// for mysql mode
// in mysql mode: index_1(c1, c2) =  index_2(c2, c1)
int ObDDLResolver::check_indexes_on_same_cols(const ObTableSchema& table_schema,
    const share::schema::ObTableSchema& input_index_table_schema, ObSchemaChecker& schema_checker,
    bool& has_other_indexes_on_same_cols)
{
  int ret = OB_SUCCESS;
  uint64_t same_indexes_cnt = 0;
  ObSEArray<ObString, 8> input_index_columns_name;
  has_other_indexes_on_same_cols = false;
  ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;

  if (OB_FAIL(ObResolverUtils::get_columns_name_from_index_table_schema(
          input_index_table_schema, input_index_columns_name))) {
    LOG_WARN("get columns name from input index table schema failed", K(ret));
  } else if (OB_FAIL(table_schema.get_simple_index_infos_without_delay_deleted_tid(simple_index_infos))) {
    LOG_WARN("get simple_index_infos without delay_deleted_tid failed", K(ret));
  }
  for (int64_t i = 0; OB_SUCC(ret) && !has_other_indexes_on_same_cols && i < simple_index_infos.count(); ++i) {
    const ObTableSchema* index_table_schema = NULL;
    bool is_match = false;
    if (OB_FAIL(schema_checker.get_table_schema(simple_index_infos.at(i).table_id_, index_table_schema))) {
      LOG_WARN("get_table_schema failed", K(ret), "table id", simple_index_infos.at(i).table_id_);
    } else if (OB_ISNULL(index_table_schema)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("table schema should not be null", K(ret));
    } else {
      ObSEArray<ObString, 8> index_columns_name;
      if (OB_FAIL(ObResolverUtils::get_columns_name_from_index_table_schema(*index_table_schema, index_columns_name))) {
        LOG_WARN("get columns name from compared index table schema failed", K(ret));
      } else if (OB_FAIL(
                     ObResolverUtils::check_match_columns(input_index_columns_name, index_columns_name, is_match))) {
        LOG_WARN("Failed to check_match_columns", K(ret));
      } else if (true == is_match) {
        ++same_indexes_cnt;
        if (same_indexes_cnt > 1) {
          has_other_indexes_on_same_cols = true;
        }
      }
    }
  }
  return ret;
}

// for oracle mode
// in oracle mode:  index_1(c1, c2) != index_2(c2, c1)
int ObDDLResolver::check_indexes_on_same_cols(const ObTableSchema& table_schema,
    const ObCreateIndexArg& create_index_arg, ObSchemaChecker& schema_checker, bool& has_other_indexes_on_same_cols)
{
  int ret = OB_SUCCESS;
  has_other_indexes_on_same_cols = false;
  ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;

  if (OB_FAIL(table_schema.get_simple_index_infos_without_delay_deleted_tid(simple_index_infos))) {
    LOG_WARN("get simple_index_infos without delay_deleted_tid failed", K(ret));
  }
  for (int64_t i = 0; OB_SUCC(ret) && !has_other_indexes_on_same_cols && i < simple_index_infos.count(); ++i) {
    const ObTableSchema* index_table_schema = NULL;
    if (OB_FAIL(schema_checker.get_table_schema(simple_index_infos.at(i).table_id_, index_table_schema))) {
      LOG_WARN("get_table_schema failed", K(ret), "table id", simple_index_infos.at(i).table_id_);
    } else if (OB_ISNULL(index_table_schema)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("table schema should not be null", K(ret));
    } else if (OB_FAIL(ObResolverUtils::check_match_columns_strict_with_order(
                   index_table_schema, create_index_arg, has_other_indexes_on_same_cols))) {
      LOG_WARN("Failed to check_match_columns", K(ret));
    }
  }

  return ret;
}

int ObDDLResolver::check_index_name_duplicate(const ObTableSchema& table_schema,
    const ObCreateIndexArg& create_index_arg, ObSchemaChecker& schema_checker, bool& has_same_index_name)
{
  int ret = OB_SUCCESS;
  has_same_index_name = false;
  ObString index_name;
  ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;

  if (OB_FAIL(table_schema.get_simple_index_infos_without_delay_deleted_tid(simple_index_infos))) {
    LOG_WARN("get simple_index_infos without delay_deleted_tid failed", K(ret));
  }
  for (int64_t i = 0; OB_SUCC(ret) && !has_same_index_name && i < simple_index_infos.count(); ++i) {
    const ObTableSchema* index_table_schema = NULL;
    if (OB_FAIL(schema_checker.get_table_schema(simple_index_infos.at(i).table_id_, index_table_schema))) {
      LOG_WARN("get_table_schema failed", K(ret), "table id", simple_index_infos.at(i).table_id_);
    } else if (OB_ISNULL(index_table_schema)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("table schema should not be null", K(ret));
    } else if (OB_FAIL(index_table_schema->get_index_name(index_name))) {
      LOG_WARN("Failed to get_index_name", K(ret));
    } else if (0 == index_name.compare(create_index_arg.index_name_)) {
      has_same_index_name = true;
    }
  }

  return ret;
}

// child 5 of root node, resolve index partition node,
// 1 this index is global, we need to first generate index schema,
//   than resolve global index partition info
// 2 this index is local, an error is raised since we cannot specify
//   partition info for a local index
int ObDDLResolver::resolve_index_partition_node(ParseNode* index_partition_node, ObCreateIndexStmt* crt_idx_stmt)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(NULL == index_partition_node) || OB_UNLIKELY(NULL == crt_idx_stmt)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(index_partition_node), KP(crt_idx_stmt));
  } else {
    ObTableSchema& index_schema = crt_idx_stmt->get_create_index_arg().index_schema_;
    if (NULL == index_partition_node) {
      // part method is not specified
    } else if (!global_) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("partitioned local index is not supported", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "partitioned local index");
    } else if (!index_schema.is_global_index_table()) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN(
          "non global index with partition option not supported", K(ret), "index_type", index_schema.get_index_type());
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "non global index with partition option");
    } else {
      if (OB_FAIL(resolve_partition_node(crt_idx_stmt, index_partition_node, index_schema))) {
        LOG_WARN("failed to resolve partition node", K(ret));
        // check valid max_used_part_id
      } else if (OB_FAIL(check_max_used_part_id_valid(index_schema, max_used_part_id_))) {
        LOG_WARN("max used part id valid", K(ret), K(max_used_part_id_), K(index_schema));
      } else {
        crt_idx_stmt->set_max_used_part_id(max_used_part_id_);
      }
      if (OB_FAIL(ret)) {
      } else if (PARTITION_LEVEL_ZERO == index_schema.get_part_level() ||
                 PARTITION_LEVEL_ONE == index_schema.get_part_level()) {
        // good
      } else if (PARTITION_LEVEL_TWO == index_schema.get_part_level()) {
        ret = OB_NOT_SUPPORTED;
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "index table with sub-partitions");
        LOG_WARN("index table with two level partitions not support", K(ret));
      }
    }
    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(check_key_cover_partition_column(crt_idx_stmt, index_schema))) {
      LOG_WARN("fail to check key cover partition column", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::check_key_cover_partition_keys(const bool is_range_part,
    const common::ObPartitionKeyInfo& part_key_info, share::schema::ObTableSchema& index_schema)
{
  int ret = OB_SUCCESS;
  for (int64_t i = 0; OB_SUCC(ret) && i < part_key_info.get_size(); ++i) {
    ObSEArray<uint64_t, 8> cascaded_columns;
    uint64_t column_id = OB_INVALID_ARGUMENT;
    const ObColumnSchemaV2* column_schema = NULL;
    if (OB_FAIL(part_key_info.get_column_id(i, column_id))) {
      LOG_WARN("fail to get column id", K(ret));
    } else if (NULL == (column_schema = index_schema.get_column_schema(column_id))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("column schema is null", K(ret));
    } else if (column_schema->get_index_position() > 0) {
      if (is_range_part) {
        if (column_schema->get_index_position() != i + 1) {
          ret = OB_NOT_SUPPORTED;
          LOG_WARN("partition columns not prefix of index columns not support", K(ret));
          LOG_USER_ERROR(OB_NOT_SUPPORTED, "partition columns not prefix of index columns");
        }
      }
    } else if (!column_schema->is_generated_column()) {
      ret = OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF;
      LOG_WARN("global index should cover all partition column of global index", K(ret));
      LOG_USER_ERROR(OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, "GLOBAL INDEX");
    } else if (is_range_part) {
      ret = OB_NOT_SUPPORTED;
      LOG_WARN("range partition on generated column in global index not support", K(ret));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "range partition on generated column in global index");
    } else if (OB_FAIL(column_schema->get_cascaded_column_ids(cascaded_columns))) {
      LOG_WARN("fail to get cascaded columns ids", K(ret));
    } else {
      for (int64_t j = 0; OB_SUCC(ret) && j < cascaded_columns.count(); ++j) {
        uint64_t cascaded_column_id = cascaded_columns.at(j);
        const ObColumnSchemaV2* cascaded_column = NULL;
        if (NULL == (cascaded_column = index_schema.get_column_schema(cascaded_column_id))) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("column schema is null", K(ret));
        } else if (column_schema->get_index_position() > 0) {
          // good, caccaded column is part the index column
        } else {
          ret = OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF;
          LOG_WARN("global index should cover all partition column of global index", K(ret));
          LOG_USER_ERROR(OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, "GLOBAL INDEX");
        }
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_key_cover_partition_column(ObCreateIndexStmt* crt_idx_stmt, ObTableSchema& index_schema)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(NULL == crt_idx_stmt)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else if (global_) {
    if (INDEX_TYPE_NORMAL_GLOBAL == crt_idx_stmt->get_create_index_arg().index_type_ ||
        INDEX_TYPE_UNIQUE_GLOBAL == crt_idx_stmt->get_create_index_arg().index_type_) {
      const common::ObPartitionKeyInfo& part_key_info = index_schema.get_partition_key_info();
      const common::ObPartitionKeyInfo& subpart_key_info = index_schema.get_subpartition_key_info();
      if (!index_schema.is_partitioned_table()) {
        // not a partition index, good
      } else if (OB_FAIL(check_key_cover_partition_keys(index_schema.is_range_part(), part_key_info, index_schema))) {
        LOG_WARN("fail to check key cover", K(ret));
      } else if (OB_FAIL(
                     check_key_cover_partition_keys(index_schema.is_range_subpart(), subpart_key_info, index_schema))) {
        LOG_WARN("fail to check key cover", K(ret));
      } else {
      }  // no more to do
    } else {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpected index type", K(ret), "index_type", crt_idx_stmt->get_create_index_arg().index_type_);
    }
  } else {
    // no need to check
  }
  return ret;
}

int ObDDLResolver::generate_global_index_schema(ObCreateIndexStmt* crt_idx_stmt)
{
  int ret = OB_SUCCESS;
  const share::schema::ObTableSchema* table_schema = NULL;
  ObTableSchema& index_schema = crt_idx_stmt->get_create_index_arg().index_schema_;
  if (OB_UNLIKELY(NULL == crt_idx_stmt)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret));
  } else if (!global_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("should not build global schema on a local index", K(ret));
  } else if (OB_UNLIKELY(NULL == schema_checker_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("schema checker ptr is null", K(ret));
  } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
                 crt_idx_stmt->get_create_index_arg().database_name_,
                 crt_idx_stmt->get_create_index_arg().table_name_,
                 false /* is index table*/,
                 table_schema))) {
    if (OB_TABLE_NOT_EXIST == ret) {
      LOG_USER_ERROR(OB_TABLE_NOT_EXIST,
          to_cstring(crt_idx_stmt->get_create_index_arg().database_name_),
          to_cstring(crt_idx_stmt->get_create_index_arg().table_name_));
      LOG_WARN("table not exist",
          K(ret),
          "database_name",
          crt_idx_stmt->get_create_index_arg().database_name_,
          "table_name",
          crt_idx_stmt->get_create_index_arg().table_name_);
    } else {
      LOG_WARN("fail to get table schema", K(ret));
    }
  } else if (OB_UNLIKELY(NULL == table_schema)) {
    ret = OB_TABLE_NOT_EXIST;
    LOG_USER_ERROR(OB_TABLE_NOT_EXIST,
        to_cstring(crt_idx_stmt->get_create_index_arg().database_name_),
        to_cstring(crt_idx_stmt->get_create_index_arg().table_name_));
    LOG_WARN("table not exist",
        K(ret),
        "database_name",
        crt_idx_stmt->get_create_index_arg().database_name_,
        "table_name",
        crt_idx_stmt->get_create_index_arg().table_name_);
  } else if (!GCONF.enable_sys_table_ddl && !table_schema->is_user_table() && !table_schema->is_tmp_table()) {
    ret = OB_ERR_WRONG_OBJECT;
    LOG_USER_ERROR(OB_ERR_WRONG_OBJECT,
        to_cstring(crt_idx_stmt->get_create_index_arg().database_name_),
        to_cstring(crt_idx_stmt->get_create_index_arg().table_name_),
        "BASE_TABLE");
    ObTableType table_type = table_schema->get_table_type();
    LOG_WARN("Not support to create index on non-normal table",
        K(ret),
        K(table_type),
        "arg",
        crt_idx_stmt->get_create_index_arg());
  } else {
    ObArray<ObColumnSchemaV2*> gen_columns;
    ObCreateIndexArg& create_index_arg = crt_idx_stmt->get_create_index_arg();
    ObCreateIndexArg my_create_index_arg;
    index_schema.set_table_type(USER_INDEX);
    index_schema.set_index_type(create_index_arg.index_type_);
    ObTableSchema new_table_schema;
    if (OB_FAIL(new_table_schema.assign(*table_schema))) {
      LOG_WARN("fail to assign schema", K(ret));
    } else if (OB_FAIL(my_create_index_arg.assign(create_index_arg))) {
      LOG_WARN("fail to assign index arg", K(ret));
    } else if (OB_FAIL(share::ObIndexBuilderUtil::adjust_expr_index_args(
                   my_create_index_arg, new_table_schema, gen_columns))) {
      LOG_WARN("fail to adjust expr index args", K(ret));
    } else if (OB_FAIL(do_generate_global_index_schema(my_create_index_arg, new_table_schema))) {
      LOG_WARN("fail to do generate global index schema", K(ret));
    } else if (OB_FAIL(index_schema.assign(my_create_index_arg.index_schema_))) {
      LOG_WARN("fail to assign schema", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::do_generate_global_index_schema(
    ObCreateIndexArg& create_index_arg, share::schema::ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  ObTableSchema& index_schema = create_index_arg.index_schema_;
  if (OB_FAIL(share::ObIndexBuilderUtil::set_index_table_columns(create_index_arg, table_schema, index_schema))) {
    LOG_WARN("fail to set index table columns", K(ret));
  } else {
  }  // no more to do
  return ret;
}

int ObDDLResolver::resolve_check_constraint_node(
    const ParseNode& cst_node, ObSEArray<ObConstraint, 4>& csts, const share::schema::ObColumnSchemaV2* column_schema)
{
  int ret = OB_SUCCESS;
  if ((share::is_mysql_mode() && (cst_node.num_child_ != 2)) ||
      (share::is_oracle_mode() && (cst_node.num_child_ != 3))) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "the num_child of constraint_node is wrong.", K(cst_node.num_child_), K(ret));
  } else {
    ObString cst_name;
    ParseNode* cst_name_node = cst_node.children_[0];
    ParseNode* cst_check_expr_node = cst_node.children_[1];
    ParseNode* cst_check_state_node = NULL;
    if (share::is_oracle_mode()) {
      cst_check_state_node = cst_node.children_[2];
    }
    if (OB_ISNULL(cst_check_expr_node)) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "NULL ptr", K(ret), K(cst_check_expr_node));
    } else if (OB_ISNULL(cst_name_node)) {
      if (share::is_mysql_mode()) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "NULL ptr", K(ret), K(cst_name_node));
      } else if (share::is_oracle_mode()) {
        if (OB_FAIL(ObTableSchema::create_cons_name_automatically(
                cst_name, table_name_, *allocator_, CONSTRAINT_TYPE_CHECK))) {
          SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
        }
      }
    } else {
      cst_name.assign_ptr(cst_name_node->str_value_, static_cast<int32_t>(cst_name_node->str_len_));
    }
    if (OB_SUCC(ret)) {
      ObConstraint cst;
      if (cst_name.length() > OB_MAX_CONSTRAINT_NAME_LENGTH) {
        ret = OB_ERR_TOO_LONG_IDENT;
        LOG_WARN("constraint_name length overflow", K(ret), K(cst_name.length()));
      } else {
        ObTableSchema tmp_table_schema;
        ObRawExpr* check_expr = NULL;
        if (OB_FAIL(get_table_schema_for_check(tmp_table_schema))) {
          LOG_WARN("get table schema failed", K(ret), K(cst_name));
        } else {
          for (uint64_t i = 0; OB_SUCC(ret) && i < csts.count(); ++i) {
            if (csts.at(i).get_constraint_name_str() == cst_name) {
              ret = OB_ERR_CONSTRAINT_NAME_DUPLICATE;
              LOG_WARN("duplicate check constraint name", K(ret), K(cst_name));
            }
          }
        }
        if (OB_SUCC(ret)) {
          if (OB_FAIL(cst.set_constraint_name(cst_name))) {
            LOG_WARN("set constraint name failed", K(ret), K(cst_name));
          } else if (OB_FAIL(resolve_check_constraint_expr(
                         params_, cst_check_expr_node, tmp_table_schema, cst, check_expr, column_schema))) {
            LOG_WARN("resolver constraint expr failed", K(ret));
          } else {
            // resolve constranit_state in oracle mode
            if (share::is_oracle_mode()) {
              if (OB_FAIL(resolve_check_cst_state_node(cst_check_state_node, cst))) {
                SQL_RESV_LOG(WARN, "fail to resolve check cst state node", K(ret));
              }
            }
            if (OB_SUCC(ret)) {
              cst.set_constraint_type(CONSTRAINT_TYPE_CHECK);
              ret = csts.push_back(cst);
            }
          }
        }
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_check_cst_state_node(const ParseNode* cst_check_state_node, ObConstraint& cst)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(cst_check_state_node)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "cst_check_state_node is null ptr", K(ret));
  } else if (T_CONSTRAINT_STATE != cst_check_state_node->type_) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(
        WARN, "cst_check_state_node->type_ must be T_CONSTRAINT_STATE", K(ret), K(cst_check_state_node->type_));
  } else if (cst_check_state_node->num_child_ != 4) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "the num_child of cst_check_state_node is wrong.", K(ret), K(cst_check_state_node->num_child_));
  } else if (OB_NOT_NULL(cst_check_state_node->children_[1])) {
    // in oracle mode: check constraint with using index option, report parser error.
    // https://docs.oracle.com/cd/E11882_01/server.112/e41084/clauses002.htm#SQLRF52180
    ret = OB_ERR_PARSER_SYNTAX;
    SQL_RESV_LOG(WARN, "check constraint can't assign state of using index", K(ret));
  } else {
    if (OB_NOT_NULL(cst_check_state_node->children_[0])) {
      cst.set_rely_flag(T_RELY_CONSTRAINT == cst_check_state_node->children_[0]->type_ ? true : false);
    }
    if (OB_NOT_NULL(cst_check_state_node->children_[2])) {
      cst.set_enable_flag(T_ENABLE_CONSTRAINT == cst_check_state_node->children_[2]->type_ ? true : false);
      cst.set_validate_flag(T_ENABLE_CONSTRAINT == cst_check_state_node->children_[2]->type_ ? true : false);
    }
    if (OB_NOT_NULL(cst_check_state_node->children_[3])) {
      cst.set_validate_flag(T_VALIDATE_CONSTRAINT == cst_check_state_node->children_[3]->type_ ? true : false);
    }
  }
  return ret;
}

int ObDDLResolver::resolve_pk_constraint_node(
    const ParseNode& pk_cst_node, common::ObString pk_name, ObSEArray<ObConstraint, 4>& csts)
{
  int ret = OB_SUCCESS;
  ObString cst_name;

  if ((T_PRIMARY_KEY != pk_cst_node.type_) && (T_COLUMN_DEFINITION != pk_cst_node.type_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "node type is wrong.", K(ret), K(pk_cst_node.type_));
  } else if (T_PRIMARY_KEY == pk_cst_node.type_) {
    // case: create table t1(c1 int, primary key(c1));
    if (pk_cst_node.num_child_ != 2) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "the num_child of constraint_node is wrong.", K(pk_cst_node.num_child_), K(ret));
    } else {
      ParseNode* cst_name_node = pk_cst_node.children_[1];
      if (OB_ISNULL(cst_name_node)) {
        // set default pk constraint name if not specified
        if (OB_FAIL(ObTableSchema::create_cons_name_automatically(
                cst_name, table_name_, *allocator_, CONSTRAINT_TYPE_PRIMARY_KEY))) {
          SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
        }
      } else {
        cst_name.assign_ptr(cst_name_node->str_value_, static_cast<int32_t>(cst_name_node->str_len_));
      }
    }
  } else {
    if (NULL == pk_name.ptr()) {
      if (OB_FAIL(ObTableSchema::create_cons_name_automatically(
              cst_name, table_name_, *allocator_, CONSTRAINT_TYPE_PRIMARY_KEY))) {
        SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
      }
    } else {
      cst_name.assign_ptr(pk_name.ptr(), pk_name.length());
    }
  }
  if (OB_SUCC(ret)) {
    ObConstraint cst;
    if (cst_name.length() > OB_MAX_CONSTRAINT_NAME_LENGTH) {
      ret = OB_ERR_TOO_LONG_IDENT;
      LOG_WARN("constraint_name length overflow", K(ret), K(cst_name.length()));
    } else {
      // ObTableSchema tmp_table_schema;
      if (csts.end() != std::find_if(csts.begin(), csts.end(), [&cst_name](const ObConstraint& cst) {
            return cst_name == cst.get_constraint_name_str();
          })) {
        ret = OB_ERR_CONSTRAINT_DUPLICATE;
        LOG_WARN("duplicate constraint name", K(ret), K(cst_name));
      } else if (OB_FAIL(cst.set_constraint_name(cst_name))) {
      } else {
        cst.set_constraint_type(CONSTRAINT_TYPE_PRIMARY_KEY);
        ret = csts.push_back(cst);
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_check_constraint_expr(ObResolverParams& params, const ParseNode* node,
    ObTableSchema& table_schema, ObConstraint& constraint, ObRawExpr*& check_expr,
    const share::schema::ObColumnSchemaV2* column_schema)
{
  int ret = OB_SUCCESS;
  check_expr = NULL;
  if (OB_ISNULL(node)) {
    ret = OB_NOT_INIT;
    LOG_WARN("NULL ptr", K(node));
  } else {
    if (OB_FAIL(ObResolverUtils::resolve_check_constraint_expr(
            params, node, table_schema, constraint, check_expr, column_schema))) {
      LOG_WARN("resolve check constraint expr failed", K(ret));
    } else if (OB_ISNULL(check_expr)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("check_expr is null", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::check_uniq_allow(ObResolverParams& params, ObTableSchema& table_schema, ObCreateIndexArg& index_arg,
    ObRawExpr* part_func_expr, ObIArray<ObRawExpr*>& constraint_exprs, bool& allow)
{
  int ret = OB_SUCCESS;
  allow = false;

  ObColumnRefRawExpr* part_col_expr = NULL;
  if (!part_func_expr->is_column_ref_expr()) {
    allow = false;
  } else if (FALSE_IT(part_col_expr = static_cast<ObColumnRefRawExpr*>(part_func_expr))) {
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < index_arg.index_columns_.count() && !allow; ++i) {
      const ObString& index_col_name = index_arg.index_columns_.at(i).column_name_;
      const ObString& part_col_name = part_col_expr->get_column_name();
      if (ObCharset::case_insensitive_equal(index_col_name, part_col_name)) {
        allow = true;
      } else {
        // concern as base-column
        for (int64_t j = 0; OB_SUCC(ret) && j < constraint_exprs.count() && !allow; ++j) {
          ObOpRawExpr* check_expr = static_cast<ObOpRawExpr*>(constraint_exprs.at(j));
          ObRawExpr* child_exprs[2] = {check_expr->get_param_expr(0), check_expr->get_param_expr(1)};
          for (int64_t k = 0; OB_SUCC(ret) && k < 2 && !allow; ++k) {
            if (child_exprs[k]->is_column_ref_expr()) {
              ObColumnRefRawExpr* col_expr = static_cast<ObColumnRefRawExpr*>(child_exprs[k]);
              if (ObCharset::case_insensitive_equal(part_col_name, col_expr->get_column_name())) {
                ObColumnRefRawExpr* cmp_col_expr = NULL;
                if (!child_exprs[1 - k]->is_column_ref_expr()) {
                  cmp_col_expr = static_cast<ObColumnRefRawExpr*>(child_exprs[1 - k]->get_param_expr(0));
                } else {
                  cmp_col_expr = static_cast<ObColumnRefRawExpr*>(child_exprs[1 - k]);
                }
                if (ObCharset::case_insensitive_equal(cmp_col_expr->get_column_name(), index_col_name)) {
                  allow = true;
                }
              }
            }
          }
        }
        // check gen column
        if (OB_SUCC(ret) && !allow) {
          ObColumnSchemaV2* column_schema = NULL;
          if (OB_ISNULL(column_schema = table_schema.get_column_schema(part_col_expr->get_column_id()))) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("Failed to get column schema", K(ret), K(part_col_expr->get_column_id()));
          } else if (column_schema->is_generated_column()) {
            ObString col_def;
            ObRawExpr* gen_expr = NULL;
            if (OB_FAIL(column_schema->get_orig_default_value().get_string(col_def))) {
              LOG_WARN("get generated column definition failed", K(ret));
            } else if (OB_FAIL(ObResolverUtils::resolve_generated_column_expr(
                           params, col_def, table_schema, *column_schema, gen_expr))) {
              LOG_WARN("resolve generated column expr failed", K(ret));
            } else {
              ObString depend_part_col_name;
              bool is_expect = true;
              // check is substring or not
              if (OB_ISNULL(gen_expr)) {
                ret = OB_ERR_UNEXPECTED;
                LOG_WARN("NULL ptr", K(ret));
              } else if (T_FUN_SYS_SUBSTR != gen_expr->get_expr_type()) {
                is_expect = false;
              } else {
                ObSysFunRawExpr* sys_expr = static_cast<ObSysFunRawExpr*>(gen_expr);
                for (int64_t j = 0; OB_SUCC(ret) && j < sys_expr->get_param_count(); j++) {
                  ObRawExpr* param_expr = sys_expr->get_param_expr(j);
                  if (OB_ISNULL(param_expr)) {
                    ret = OB_ERR_UNEXPECTED;
                    LOG_WARN("NULL ptr", K(ret), K(param_expr));
                  } else if (0 == j && !param_expr->is_column_ref_expr()) {
                    is_expect = false;
                  } else if (0 != j && !param_expr->is_const_expr()) {
                    is_expect = false;
                  }
                }
                if (OB_SUCC(ret) && is_expect) {
                  depend_part_col_name =
                      static_cast<ObColumnRefRawExpr*>(sys_expr->get_param_expr(0))->get_column_name();
                }
                if (OB_SUCC(ret) && !is_expect) {
                  continue;
                }
              }
              for (int64_t j = 0; OB_SUCC(ret) && j < constraint_exprs.count() && !allow; ++j) {
                ObOpRawExpr* check_expr = static_cast<ObOpRawExpr*>(constraint_exprs.at(j));
                ObRawExpr* child_exprs[2] = {check_expr->get_param_expr(0), check_expr->get_param_expr(1)};
                ObColumnRefRawExpr* col_exprs[2] = {NULL, NULL};
                bool gen_expr_exist = false;
                bool all_col = true;
                for (int64_t k = 0; OB_SUCC(ret) && k < 2; ++k) {
                  if (child_exprs[k]->is_column_ref_expr()) {
                    col_exprs[k] = static_cast<ObColumnRefRawExpr*>(child_exprs[k]);
                  } else {
                    all_col = false;
                    col_exprs[k] = static_cast<ObColumnRefRawExpr*>(child_exprs[k]->get_param_expr(0));
                    if (!gen_expr_exist) {
                      ret = check_same_substr_expr(*child_exprs[k], *gen_expr, gen_expr_exist);
                    }
                  }
                }
                if (OB_SUCC(ret)) {
                  if (all_col || gen_expr_exist) {
                    if (ObCharset::case_insensitive_equal(col_exprs[0]->get_column_name(), index_col_name) &&
                        ObCharset::case_insensitive_equal(col_exprs[1]->get_column_name(), depend_part_col_name)) {
                      allow = true;
                    } else if (ObCharset::case_insensitive_equal(col_exprs[1]->get_column_name(), index_col_name) &&
                               ObCharset::case_insensitive_equal(
                                   col_exprs[0]->get_column_name(), depend_part_col_name)) {
                      allow = true;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::check_same_substr_expr(ObRawExpr& left, ObRawExpr& right, bool& same)
{
  int ret = OB_SUCCESS;
  same = true;

  if (left.get_expr_type() != T_FUN_SYS_SUBSTR || right.get_expr_type() != T_FUN_SYS_SUBSTR) {
    same = false;
  } else {
    ObSysFunRawExpr& sys_left = static_cast<ObSysFunRawExpr&>(left);
    ObSysFunRawExpr& sys_right = static_cast<ObSysFunRawExpr&>(right);
    if (sys_left.get_param_count() != sys_right.get_param_count()) {
      same = false;
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < sys_left.get_param_count() && same; ++i) {
        ObRawExpr* param_left = sys_left.get_param_expr(i);
        ObRawExpr* param_right = sys_right.get_param_expr(i);
        if (0 == i) {
          if (!param_left->is_column_ref_expr() || !param_right->is_column_ref_expr()) {
            same = false;
          } else {
            ObColumnRefRawExpr* col_left = static_cast<ObColumnRefRawExpr*>(param_left);
            ObColumnRefRawExpr* col_right = static_cast<ObColumnRefRawExpr*>(param_right);
            if (!ObCharset::case_insensitive_equal(col_left->get_column_name(), col_right->get_column_name())) {
              same = false;
            }
          }
        } else {
          if (!param_left->is_const_expr() || !param_right->is_const_expr()) {
            same = false;
          } else if (!param_left->same_as(*param_right)) {
            same = false;
          }
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::check_uniq_allow(ObTableSchema& table_schema, ObCreateIndexArg& index_arg, bool& allow)
{
  int ret = OB_SUCCESS;
  allow = false;

  if (table_schema.get_part_level() == PARTITION_LEVEL_ONE && table_schema.get_part_option().is_list_part()) {
    ObArenaAllocator allocator(ObModIds::OB_TEMP_VARIABLES);
    ObResolverParams params;
    ObRawExprFactory expr_factory(allocator);
    ObSQLSessionInfo empty_session;
    params.expr_factory_ = &expr_factory;
    params.allocator_ = &allocator;
    params.session_info_ = &empty_session;
    if (OB_FAIL(empty_session.init(0, 0, 0, &allocator))) {
      LOG_WARN("init empty session failed", K(ret));
    } else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
      LOG_WARN("session load default system variable failed", K(ret));
    } else {
      const share::schema::ObPartitionFuncType part_func_type = table_schema.get_part_option().get_part_func_type();
      const ParseNode* node = NULL;
      common::ObSEArray<common::ObString, 8> part_keys;
      common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
      if (OB_FAIL(ObRawExprUtils::parse_expr_node_from_str(
              table_schema.get_part_option().get_part_func_expr_str(), *params.allocator_, node))) {
        LOG_WARN("parse expr node from string failed", K(ret));
      } else if (OB_FAIL(resolve_part_func(params, node, part_func_type, table_schema, part_func_exprs, part_keys))) {
        SQL_RESV_LOG(WARN, "resolve part func failed", K(ret));
      }
      if (OB_SUCC(ret) && part_func_exprs.count() == 1) {
        ObSEArray<ObRawExpr*, 8> check_exprs;
        for (ObTableSchema::const_constraint_iterator iter = table_schema.constraint_begin();
             OB_SUCC(ret) && iter != table_schema.constraint_end();
             iter++) {
          ObConstraint cst;
          ObRawExpr* check_expr = NULL;
          if ((*iter)->get_constraint_type() != CONSTRAINT_TYPE_CHECK) {
            continue;
          } else if (OB_FAIL(ObRawExprUtils::parse_bool_expr_node_from_str(
                         (*iter)->get_check_expr_str(), *params.allocator_, node))) {
            LOG_WARN("parse expr node from string failed", K(ret));
          } else if (OB_FAIL(resolve_check_constraint_expr(params, node, table_schema, cst, check_expr))) {
            LOG_WARN("resolver constraint expr failed", K(ret));
          } else {
            ret = check_exprs.push_back(check_expr);
          }
        }
        bool tmp_allow = false;
        if (OB_FAIL(ret)) {
        } else if (OB_FAIL(check_uniq_allow(
                       params, table_schema, index_arg, part_func_exprs.at(0), check_exprs, tmp_allow))) {
          LOG_WARN("check_uniq_allowe failed", K(ret));
        } else if (tmp_allow) {
          allow = tmp_allow;
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_split_partition_range_element(const ParseNode* node,
    const share::schema::ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    common::ObIArray<ObRawExpr*>& range_value_exprs, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(node) || T_EXPR_LIST != node->type_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid_argument", K(ret), "type", node->type_);
  } else if (!in_tablegroup) {
    if (node->num_child_ != part_func_exprs.count()) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid_argument", K(ret), "node num", node->num_child_, "function num", part_func_exprs.count());
    }
  }
  ObString part_name;
  for (int i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) {
    if (OB_ISNULL(node->children_[i])) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("node is null", K(ret), K(i), "node", node->children_[i]);
    } else if (T_MAXVALUE == node->children_[i]->type_) {
      ObRawExpr* maxvalue_expr = NULL;
      ObConstRawExpr* c_expr = NULL;
      c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
      if (OB_ISNULL(c_expr)) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_WARN("failed to alloc raw expr", K(ret), K(c_expr));
      } else {
        c_expr = new (c_expr) ObConstRawExpr();
        maxvalue_expr = c_expr;
        maxvalue_expr->set_data_type(common::ObMaxType);
        if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
          LOG_WARN("array push back fail", K(ret));
        }
      }
    } else if (T_NULL == node->children_[i]->type_) {
      ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
      LOG_WARN("null value is not allowed in less than", K(ret));
    } else if (T_EXPR_LIST != node->children_[i]->type_) {
      ObRawExpr* part_value_expr = NULL;
      ObRawExpr* part_func_expr = NULL;
      if (!in_tablegroup) {
        if (OB_FAIL(part_func_exprs.at(i, part_func_expr))) {
          LOG_WARN("get part expr failed", K(ret), K(i), "size", part_func_exprs.count());
        } else if (OB_ISNULL(part_func_expr)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("part func expr is invalid", K(ret), K(i));
        } else if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(params_,
                       *(node->children_[i]),
                       part_name,
                       part_type,
                       *part_func_expr,
                       part_value_expr,
                       in_tablegroup))) {
          LOG_WARN("failed to resolve at values", K(ret));
        }
      } else {
        if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
                params_, *(node->children_[i]), part_name, part_type, part_value_expr, in_tablegroup))) {
          LOG_WARN("failed to resolve at values", K(ret));
        }
      }
      if (OB_FAIL(ret)) {
      } else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
        LOG_WARN("failed to push back raw_expr", K(ret), K(part_value_expr));
      }
    }
  }  // end for process t_expr_list
  return ret;
}

int ObDDLResolver::resolve_split_partition_list_value(const ParseNode* node,
    const share::schema::ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObDDLStmt::array_t& list_value_exprs, int64_t& expr_num, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  ObString part_name;
  ObOpRawExpr* row_expr = NULL;
  if (OB_ISNULL(node) || OB_ISNULL(params_.expr_factory_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(params_.expr_factory_));
  } else if (T_EXPR_LIST != node->type_ && T_DEFAULT != node->type_) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument node type", K(ret), "node type", node->type_);
  } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_OP_ROW, row_expr))) {
    LOG_WARN("failed to create raw expr", K(ret));
  } else if (OB_ISNULL(row_expr)) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_WARN("failed to allcoate memory", K(ret));
  } else if (T_DEFAULT == node->type_) {
    // replace default value with max
    ObRawExpr* maxvalue_expr = NULL;
    ObConstRawExpr* c_expr = NULL;
    c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
    if (OB_ISNULL(c_expr)) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
    } else {
      c_expr = new (c_expr) ObConstRawExpr();
      maxvalue_expr = c_expr;
      maxvalue_expr->set_data_type(common::ObMaxType);
      ObDDLStmt::array_t part_value_expr_array;
      if (OB_FAIL(row_expr->add_param_expr(maxvalue_expr))) {
        LOG_WARN("failed to add param expr", K(ret));
      } else if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
        LOG_WARN("array push back fail", K(ret));
      }
    }
  } else {
    ObSEArray<ObRawExpr*, 16> part_value_exprs;

    bool is_all_expr_list = false;
    if (node->num_child_ > 0) {
      is_all_expr_list = (node->children_[0]->type_ == T_EXPR_LIST);
    }
    for (int64_t j = 0; OB_SUCC(ret) && j < node->num_child_; j++) {
      part_value_exprs.reset();
      if (OB_ISNULL(node->children_[j])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("node is null", K(ret));
      } else if ((is_all_expr_list && node->children_[j]->type_ != T_EXPR_LIST) ||
                 (!is_all_expr_list && node->children_[j]->type_ == T_EXPR_LIST)) {
        ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
        LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
      } else if (!in_tablegroup &&
                 OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(
                     params_, *(node->children_[j]), part_name, part_type, part_func_exprs, part_value_exprs))) {
        LOG_WARN("resolve partition expr failed", K(ret));
      } else if (in_tablegroup && OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(params_,
                                      *(node->children_[j]),
                                      part_name,
                                      part_type,
                                      expr_num,
                                      part_value_exprs,
                                      in_tablegroup))) {
        LOG_WARN("resolve partition expr failed", K(ret));
      }
      for (int64_t k = 0; OB_SUCC(ret) && k < part_value_exprs.count(); k++) {
        if (OB_FAIL(row_expr->add_param_expr(part_value_exprs.at(k)))) {
          LOG_WARN("failed to add param expr", K(ret));
        }
      }  // end for
    }    // end for
    if (OB_FAIL(ret)) {
    } else if (part_func_exprs.count() > 1 && !is_all_expr_list) {
      if (row_expr->get_param_count() != part_func_exprs.count()) {
        ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
        LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
      }
    }

    if (OB_FAIL(ret)) {
    } else if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
      LOG_WARN("array push back fail", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::check_split_type_valid(
    const ParseNode* split_node, const share::schema::ObPartitionFuncType part_type)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(split_node) || T_SPLIT_ACTION != split_node->type_ ||
      OB_ISNULL(split_node->children_[SPLIT_PARTITION_TYPE_NODE]) || PARTITION_FUNC_TYPE_MAX == part_type) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("node type error or partition type node is null",
        K(ret),
        "node_type",
        split_node->type_,
        "split_partition_type",
        split_node->children_[SPLIT_PARTITION_TYPE_NODE],
        K(part_type));
  } else if (share::schema::is_list_part(part_type) &&
             T_SPLIT_LIST != split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_USER_ERROR(OB_ERR_UNEXPECTED, "VALUES LESS THAN or AT clause cannot be used with List partition");
    LOG_WARN("at clause cannot be used with list partition",
        K(ret),
        "node_type",
        split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_);
  } else if (share::schema::is_range_part(part_type) &&
             T_SPLIT_RANGE != split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_USER_ERROR(OB_ERR_UNEXPECTED, "expecting VALUES LESS THAN  or AT clause");
    LOG_WARN("values clause cannot be used with range partitioned",
        K(ret),
        "node_type",
        split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_);
  }
  return ret;
}

int ObDDLResolver::generate_index_name(
    ObString& index_name, IndexNameSet& current_index_name_set, const common::ObString& first_col_name)
{
  int ret = OB_SUCCESS;
  // inspect whether first_column_name is exist
  ObIndexNameHashWrapper index_key(first_col_name);
  if (OB_ISNULL(allocator_)) {
    ret = OB_NOT_INIT;
    SQL_RESV_LOG(WARN, "allocator is null.", K(ret));
  } else if (OB_HASH_EXIST != current_index_name_set.exist_refactored(index_key)) {
    if (OB_FAIL(ob_write_string(*allocator_, first_col_name, index_name))) {
      SQL_RESV_LOG(WARN, "failed to set index name to first column name", K(ret));
    }
  } else {
    char buffer[number::ObNumber::MAX_PRINTABLE_SIZE];
    ObString str;
    bool b_flag = false;
    ObIndexNameHashWrapper tmp_key;
    for (int32_t i = 2; OB_SUCC(ret) && !b_flag; ++i) {
      if (snprintf(buffer, sizeof(buffer), "%.*s_%d", first_col_name.length(), first_col_name.ptr(), i) < 0) {
        ret = OB_SIZE_OVERFLOW;
        SQL_RESV_LOG(WARN, "failed to generate buffer", K(first_col_name), K(ret));
      } else if (OB_FAIL(ob_write_string(*allocator_, ObString::make_string(buffer), str))) {
        SQL_RESV_LOG(WARN, "Can not malloc space for index name");
      } else {
        tmp_key.set_name(str);
        if (OB_HASH_EXIST != current_index_name_set.exist_refactored(tmp_key)) {
          b_flag = true;
        }
      }
    }
    index_name.assign_ptr(str.ptr(), str.length());
  }

  return ret;
}

int ObDDLResolver::resolve_foreign_key(const ParseNode* node, ObArray<int>& node_position_list)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(node)) {
    // do nothing, create table t as select ... will come here
  } else if (T_TABLE_ELEMENT_LIST != node->type_) {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_));
  } else if (OB_ISNULL(stmt_)) {
    ret = OB_NOT_INIT;
    SQL_RESV_LOG(WARN, "stmt_ is null", K(ret));
  } else if (OB_ISNULL(node->children_)) {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->children_));
  } else {
    ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
    for (int64_t i = 0; OB_SUCC(ret) && i < node_position_list.size(); ++i) {
      int child_pos = node_position_list.at(i);
      ObCreateForeignKeyArg foreign_key_arg;
      if (!(0 <= child_pos && child_pos < node->num_child_)) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "node pos out of range", K(ret), K(child_pos), K(node->num_child_));
      } else if (OB_FAIL(resolve_foreign_key_node(node->children_[child_pos], foreign_key_arg, false))) {
        SQL_RESV_LOG(WARN, "failed to resolve foreign key node", K(ret), K(child_pos));
      } else if (OB_FAIL(create_table_stmt->get_foreign_key_arg_list().push_back(foreign_key_arg))) {
        SQL_RESV_LOG(WARN, "failed to push back foreign key arg", K(ret));
      }
    }
    if (OB_SUCC(ret) && share::is_oracle_mode() &&
        OB_FAIL(ObResolverUtils::check_dup_foreign_keys_exist(create_table_stmt->get_foreign_key_arg_list()))) {
      SQL_RESV_LOG(WARN, "failed to check dup foreign keys exist", K(ret));
    }
    current_foreign_key_name_set_.reset();
  }

  return ret;
}

int ObDDLResolver::resolve_foreign_key_node(
    const ParseNode* node, obrpc::ObCreateForeignKeyArg& arg, bool is_alter_table, const ObColumnSchemaV2* column)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(node)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "node is null", K(ret));
  } else if (!is_oracle_mode()) {
    // mysql mode
    if (T_FOREIGN_KEY != node->type_ || 7 != node->num_child_ || OB_ISNULL(node->children_)) {
      ret = OB_ERR_UNEXPECTED;
      SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
    } else {
      ParseNode* child_columns = node->children_[0];
      ParseNode* parent_table = node->children_[1];
      ParseNode* parent_columns = node->children_[2];
      ParseNode* reference_options = node->children_[3];
      ParseNode* constraint_name = node->children_[4];
      ParseNode* foreign_key_name = node->children_[5];
      UNUSED(foreign_key_name);
      ParseNode* match_options = node->children_[6];
      if (OB_FAIL(resolve_table_relation_node(parent_table, arg.parent_table_, arg.parent_database_))) {
        LOG_WARN("failed to resolve foreign key parent table", K(ret));
      } else if (OB_FAIL(resolve_foreign_key_columns(child_columns, arg.child_columns_))) {
        LOG_WARN("failed to resolve foreign key child columns", K(ret));
      } else if (OB_FAIL(resolve_foreign_key_columns(parent_columns, arg.parent_columns_))) {
        LOG_WARN("failed to resolve foreign key parent columns", K(ret));
      } else if (OB_FAIL(resolve_foreign_key_options(reference_options, arg.update_action_, arg.delete_action_))) {
        LOG_WARN("failed to resolve foreign key options", K(ret));
      } else if (OB_FAIL(resolve_foreign_key_name(constraint_name, arg.foreign_key_name_))) {
        LOG_WARN("failed to resolve foreign key name", K(ret));
      } else if (OB_FAIL(check_foreign_key_reference(arg, is_alter_table, NULL))) {
        LOG_WARN("failed to check reference columns", K(ret));
      } else if (OB_FAIL(resolve_match_options(match_options))) {
        LOG_WARN("failed to resolve match options", K(ret));
      }
    }
  } else {
    // oracle mode
    if (NULL == column) {  // table level foreign key in oracle mode
      if (T_FOREIGN_KEY != node->type_ || 4 != node->num_child_ || OB_ISNULL(node->children_)) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
      } else {
        ParseNode* constraint_name = node->children_[0];
        ParseNode* child_columns = node->children_[1];
        ParseNode* references_clause_node = node->children_[2];
        ParseNode* fk_enable_state_node = node->children_[3];
        ParseNode* parent_table = nullptr;
        ParseNode* parent_columns = nullptr;
        ParseNode* reference_options = nullptr;
        if (OB_ISNULL(references_clause_node)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("failed to resolve references clause, node is null", K(ret));
        } else {
          // resolve references_clause
          if (T_REFERENCES_CLAUSE != references_clause_node->type_ || 3 != references_clause_node->num_child_ ||
              OB_ISNULL(references_clause_node->children_)) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN,
                "invalid argument",
                K(ret),
                K(references_clause_node->type_),
                K(references_clause_node->num_child_),
                K(references_clause_node->children_));
          } else {
            parent_table = references_clause_node->children_[0];
            parent_columns = references_clause_node->children_[1];
            reference_options = references_clause_node->children_[2];
          }
        }
        if (OB_SUCC(ret)) {
          if (OB_FAIL(resolve_table_relation_node(parent_table, arg.parent_table_, arg.parent_database_))) {
            LOG_WARN("failed to resolve foreign key parent table", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_columns(child_columns, arg.child_columns_))) {
            LOG_WARN("failed to resolve foreign key child columns", K(ret));
          } else if (OB_FAIL(resolve_fk_referenced_columns_oracle(
                         parent_columns, arg, is_alter_table, arg.parent_columns_))) {
            LOG_WARN("failed to resolve foreign key parent columns in oracle mode", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_option(reference_options, arg.update_action_, arg.delete_action_))) {
            LOG_WARN("failed to resolve foreign key options", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_name(constraint_name, arg.foreign_key_name_))) {
            LOG_WARN("failed to resolve foreign key name", K(ret));
          } else if (OB_FAIL(check_foreign_key_reference(arg, is_alter_table, NULL))) {
            LOG_WARN("failed to check reference columns", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_state(fk_enable_state_node, arg))) {
            LOG_WARN("failed to resolve foreign key enable_state", K(ret));
          }
        }
      }
    } else {  // column level foreign key in oracle mode
      if (T_FOREIGN_KEY != node->type_ || 3 != node->num_child_ || OB_ISNULL(node->children_)) {
        ret = OB_ERR_UNEXPECTED;
        SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
      } else {
        ParseNode* constraint_name = node->children_[0];
        ParseNode* references_clause_node = node->children_[1];
        ParseNode* fk_enable_state_node = node->children_[2];
        ParseNode* parent_table = nullptr;
        ParseNode* parent_columns = nullptr;
        ParseNode* reference_options = nullptr;
        if (OB_ISNULL(references_clause_node)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("failed to resolve references clause, node is null", K(ret));
        } else {
          // resolve references_clause
          if (T_REFERENCES_CLAUSE != references_clause_node->type_ || 3 != references_clause_node->num_child_ ||
              OB_ISNULL(references_clause_node->children_)) {
            ret = OB_ERR_UNEXPECTED;
            SQL_RESV_LOG(WARN,
                "invalid argument",
                K(ret),
                K(references_clause_node->type_),
                K(references_clause_node->num_child_),
                K(references_clause_node->children_));
          } else {
            parent_table = references_clause_node->children_[0];
            parent_columns = references_clause_node->children_[1];
            reference_options = references_clause_node->children_[2];
          }
        }
        if (OB_SUCC(ret)) {
          if (OB_FAIL(resolve_table_relation_node(parent_table, arg.parent_table_, arg.parent_database_))) {
            LOG_WARN("failed to resolve foreign key parent table", K(ret));
          } else if (OB_FAIL(arg.child_columns_.push_back(
                         ObString(column->get_column_name_str().length(), column->get_column_name_str().ptr())))) {
            LOG_WARN("failed to push back column name", K(ret));
          } else if (OB_FAIL(resolve_fk_referenced_columns_oracle(
                         parent_columns, arg, is_alter_table, arg.parent_columns_))) {
            LOG_WARN("failed to resolve foreign key parent columns", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_option(reference_options, arg.update_action_, arg.delete_action_))) {
            LOG_WARN("failed to resolve foreign key options", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_name(constraint_name, arg.foreign_key_name_))) {
            LOG_WARN("failed to resolve foreign key name", K(ret));
          } else if (OB_FAIL(check_foreign_key_reference(arg, is_alter_table, column))) {
            LOG_WARN("failed to check reference columns", K(ret));
          } else if (OB_FAIL(resolve_foreign_key_state(fk_enable_state_node, arg))) {
            LOG_WARN("failed to resolve foreign key enable_state", K(ret));
          }
        }
      }
    }

  }  // end oracle mode

  return ret;
}

int ObDDLResolver::resolve_foreign_key_columns(const ParseNode* node, ObIArray<ObString>& columns)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(node)) {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "node is null", K(ret));
  } else if (OB_ISNULL(node->children_)) {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) {
      ParseNode* column = node->children_[i];
      if (OB_ISNULL(column)) {
        ret = OB_INVALID_ARGUMENT;
        SQL_RESV_LOG(WARN, "child is null", K(ret));
      } else if (OB_ISNULL(column->str_value_)) {
        ret = OB_INVALID_ARGUMENT;
        SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(column->type_), K(column->str_value_));
      } else if (OB_FAIL(columns.push_back(ObString(column->str_len_, column->str_value_)))) {
        LOG_WARN("failed to push back column name", K(ret), K(column->str_value_));
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_fk_referenced_columns_oracle(
    const ParseNode* node, const obrpc::ObCreateForeignKeyArg& arg, bool is_alter_table, ObIArray<ObString>& columns)
{
  int ret = OB_SUCCESS;

  if (share::is_oracle_mode() && OB_ISNULL(node)) {
    // oracle mode: ref column can be default, will auto ref parent table's pk column
    const ObTableSchema* parent_table_schema = NULL;
    if (0 == arg.parent_table_.case_compare(table_name_) && 0 == arg.parent_database_.case_compare(database_name_) &&
        !is_alter_table) {
      // create table with self-ref foreign key
      if (OB_ISNULL(static_cast<ObCreateTableStmt*>(stmt_))) {
        ret = OB_NOT_INIT;
        SQL_RESV_LOG(WARN, "stmt_ is null.", K(ret));
      } else {
        parent_table_schema = &static_cast<ObCreateTableStmt*>(stmt_)->get_create_table_arg().schema_;
        if (OB_ISNULL(parent_table_schema)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("parent table schema is null", K(ret));
        }
      }
    } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
                   arg.parent_database_,
                   arg.parent_table_,
                   false,
                   parent_table_schema))) {
      LOG_WARN("table is not exist", K(ret), K(arg.parent_database_), K(arg.parent_table_));
    } else if (OB_ISNULL(parent_table_schema)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("parent table schema is null", K(ret));
    }
    if (OB_SUCC(ret)) {
      const ObRowkeyInfo& rowkey_info = parent_table_schema->get_rowkey_info();
      for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_info.get_size(); ++i) {
        uint64_t column_id = 0;
        const ObColumnSchemaV2* col_schema = NULL;
        if (OB_FAIL(rowkey_info.get_column_id(i, column_id))) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("fail to get rowkey info", K(ret), K(i), K(rowkey_info));
        } else if (NULL == (col_schema = parent_table_schema->get_column_schema(column_id))) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("get index column schema failed", K(ret));
        } else if (col_schema->is_hidden() || col_schema->is_shadow_column()) {
          // do nothing
        } else if (OB_FAIL(columns.push_back(col_schema->get_column_name()))) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("push back index column failed", K(ret));
        }
      }
      if (OB_SUCC(ret) && (0 == columns.count())) {
        ret = OB_ERR_REFERENCED_TABLE_HAS_NO_PK;
        LOG_WARN("referenced table does not have a primary key", K(ret), KPC(parent_table_schema));
      }
    }
  } else if (OB_FAIL(resolve_foreign_key_columns(node, columns))) {
    LOG_WARN("failed to resolve foreign key columns", K(ret));
  }

  return ret;
}

int ObDDLResolver::resolve_foreign_key_options(
    const ParseNode* node, ObReferenceAction& update_action, ObReferenceAction& delete_action)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(node)) {
    // nothing.
  } else if (T_REFERENCE_OPTION_LIST != node->type_ || node->num_child_ > 2) {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_));
  } else if (NULL != node->children_) {
    update_action = ACTION_INVALID;
    delete_action = ACTION_INVALID;
    ParseNode* option_node = NULL;
    for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) {
      option_node = node->children_[i];
      ObReferenceAction action = ACTION_INVALID;
      if (OB_ISNULL(option_node)) {
        ret = OB_INVALID_ARGUMENT;
        SQL_RESV_LOG(WARN, "option node is null", K(ret), K(i));
      } else {
        switch (option_node->int32_values_[1]) {
          case T_RESTRICT:
            action = ACTION_RESTRICT;
            break;
          case T_CASCADE:
            action = ACTION_CASCADE;
            break;
          case T_SET_NULL:
            // action = ACTION_SET_NULL;
            ret = OB_NOT_SUPPORTED;
            LOG_USER_ERROR(OB_NOT_SUPPORTED, "create foreign key with set null option");
            break;
          case T_NO_ACTION:
            action = ACTION_NO_ACTION;
            break;
          case T_SET_DEFAULT:
            ret = OB_ERR_CANNOT_ADD_FOREIGN;
            SQL_RESV_LOG(WARN,
                "Cannot add foreign key constraint, because the key word of action is ACTION_SET_DEFAULT",
                K(ret),
                K(node->int32_values_[1]));
            break;
          default:
            ret = OB_INVALID_ARGUMENT;
            SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[1]));
            break;
        }
      }
      if (OB_SUCC(ret)) {
        switch (option_node->int32_values_[0]) {
          case T_UPDATE:
            if (ACTION_INVALID != update_action) {
              ret = OB_INVALID_ARGUMENT;
              SQL_RESV_LOG(WARN, "mutli update option", K(ret));
            } else {
              update_action = action;
            }
            break;
          case T_DELETE:
            if (ACTION_INVALID != delete_action) {
              ret = OB_INVALID_ARGUMENT;
              SQL_RESV_LOG(WARN, "mutli delete option", K(ret));
            } else {
              delete_action = action;
            }
            break;
          default:
            ret = OB_INVALID_ARGUMENT;
            SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[0]));
            break;
        }
      }
    }
  }
  if (OB_SUCC(ret)) {
    if (ACTION_INVALID == update_action) {
      update_action = ACTION_RESTRICT;
    }
    if (ACTION_INVALID == delete_action) {
      delete_action = ACTION_RESTRICT;
    }
  }

  return ret;
}

// for oracle mode
int ObDDLResolver::resolve_foreign_key_option(const ParseNode* option_node,
    share::schema::ObReferenceAction& update_action, share::schema::ObReferenceAction& delete_action)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(option_node)) {
    // do nothing.
  } else if (T_REFERENCE_OPTION != option_node->type_) {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(option_node->type_));
  } else {
    ObReferenceAction action = ACTION_INVALID;
    switch (option_node->int32_values_[1]) {
      case T_CASCADE:
        action = ACTION_CASCADE;
        break;
      case T_SET_NULL:
        // action = ACTION_SET_NULL;
        ret = OB_NOT_SUPPORTED;
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "create foreign key with set null option");
        break;
      default:
        ret = OB_INVALID_ARGUMENT;
        SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[1]));
        break;
    }
    if (OB_SUCC(ret)) {
      switch (option_node->int32_values_[0]) {
        case T_DELETE:
          delete_action = action;
          break;
        default:
          ret = OB_INVALID_ARGUMENT;
          SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[0]));
          break;
      }
    }
  }
  // default value is ACTION_RESTRICT
  if (OB_SUCC(ret)) {
    if (ACTION_INVALID == update_action) {
      update_action = ACTION_RESTRICT;
    }
    if (ACTION_INVALID == delete_action) {
      delete_action = ACTION_RESTRICT;
    }
  }

  return ret;
}

int ObDDLResolver::resolve_foreign_key_name(const ParseNode* constraint_node, ObString& foreign_key_name)
{
  int ret = OB_SUCCESS;
  foreign_key_name.reset();

  if (OB_NOT_NULL(constraint_node)) {
    if (!is_oracle_mode()) {
      // mysql mode
      const ParseNode* constraint_name = NULL;
      if (T_CHECK_CONSTRAINT != constraint_node->type_ || 1 != constraint_node->num_child_ ||
          OB_ISNULL(constraint_node->children_)) {
        ret = OB_INVALID_ARGUMENT;
        SQL_RESV_LOG(WARN,
            "invalid argument",
            K(ret),
            K(constraint_node->type_),
            K(constraint_node->num_child_),
            KP(constraint_node->children_));
      } else if (OB_NOT_NULL(constraint_name = constraint_node->children_[0])) {
        foreign_key_name.assign_ptr(constraint_name->str_value_, static_cast<int32_t>(constraint_name->str_len_));
        // check if fk name duplicated in create_table
        ObForeignKeyNameHashWrapper fk_key(foreign_key_name);
        if (OB_HASH_EXIST == (ret = current_foreign_key_name_set_.exist_refactored(fk_key))) {
          SQL_RESV_LOG(WARN, "duplicate fk name", K(ret), K(foreign_key_name));
          ret = OB_ERR_CANNOT_ADD_FOREIGN;
        } else {
          ret = OB_SUCCESS;
          if (OB_FAIL(current_foreign_key_name_set_.set_refactored(fk_key))) {
            SQL_RESV_LOG(WARN, "set foreign key name to hash set failed", K(ret), K(foreign_key_name));
          }
        }
      } else if (OB_FAIL(create_fk_cons_name_automatically(foreign_key_name))) {
        SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
      }
    } else {
      // oracle mode
      foreign_key_name.assign_ptr(constraint_node->str_value_, static_cast<int32_t>(constraint_node->str_len_));
      ObForeignKeyNameHashWrapper fk_key(foreign_key_name);
      if (OB_HASH_EXIST == (ret = current_foreign_key_name_set_.exist_refactored(fk_key))) {
        SQL_RESV_LOG(WARN, "duplicate fk name", K(ret), K(foreign_key_name));
        ret = OB_ERR_CANNOT_ADD_FOREIGN;
      } else {
        ret = OB_SUCCESS;
        if (OB_FAIL(current_foreign_key_name_set_.set_refactored(fk_key))) {
          SQL_RESV_LOG(WARN, "set foreign key name to hash set failed", K(ret), K(foreign_key_name));
        }
      }
    }
  } else if (OB_FAIL(create_fk_cons_name_automatically(foreign_key_name))) {
    SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
  }

  return ret;
}

int ObDDLResolver::resolve_foreign_key_state(const ParseNode* fk_state_node, obrpc::ObCreateForeignKeyArg& arg)
{
  int ret = OB_SUCCESS;

  if (OB_ISNULL(fk_state_node)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "cst_check_state_node is null ptr", K(ret));
  } else if (T_CONSTRAINT_STATE != fk_state_node->type_) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "fk_state_node->type_ must be T_CONSTRAINT_STATE", K(ret), K(fk_state_node->type_));
  } else if (fk_state_node->num_child_ != 4) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "the num_child of cst_check_state_node is wrong.", K(ret), K(fk_state_node->num_child_));
  } else if (OB_NOT_NULL(fk_state_node->children_[1])) {
    // https://docs.oracle.com/cd/E11882_01/server.112/e41084/clauses002.htm#SQLRF52180
    ret = OB_ERR_PARSER_SYNTAX;
    SQL_RESV_LOG(WARN, "foreign key can't assign state of using index", K(ret));
  } else {
    if (OB_NOT_NULL(fk_state_node->children_[0])) {
      arg.rely_flag_ = (T_RELY_CONSTRAINT == fk_state_node->children_[0]->type_ ? true : false);
    }
    if (OB_NOT_NULL(fk_state_node->children_[2])) {
      arg.enable_flag_ = (T_ENABLE_CONSTRAINT == fk_state_node->children_[2]->type_ ? true : false);
      arg.validate_flag_ = (T_ENABLE_CONSTRAINT == fk_state_node->children_[2]->type_ ? true : false);
    }
    if (OB_NOT_NULL(fk_state_node->children_[3])) {
      arg.validate_flag_ = (T_VALIDATE_CONSTRAINT == fk_state_node->children_[3]->type_ ? true : false);
    }
  }

  return ret;
}

int ObDDLResolver::check_foreign_key_reference(
    obrpc::ObCreateForeignKeyArg& arg, bool is_alter_table, const ObColumnSchemaV2* column)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(session_info_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "session_info_ is null.", K(ret));
  } else {
    ObCreateTableStmt* create_table_stmt = NULL;
    const ObTableSchema* child_table_schema = NULL;
    const ObTableSchema* parent_table_schema = NULL;
    ObString& database_name = arg.parent_database_;
    ObString& parent_table_name = arg.parent_table_;
    if (!is_alter_table) {
      create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
      if (OB_ISNULL(create_table_stmt)) {
        ret = OB_NOT_INIT;
        SQL_RESV_LOG(WARN, "stmt_ is null.", K(ret));
      } else {
        child_table_schema = &create_table_stmt->get_create_table_arg().schema_;
      }
    } else {  // is alter table
      ObAlterTableStmt* alter_table_stmt = static_cast<ObAlterTableStmt*>(stmt_);
      if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
              alter_table_stmt->get_org_database_name(),
              alter_table_stmt->get_org_table_name(),
              false,
              child_table_schema))) {
        LOG_WARN("table is not exist", K(database_name), K(parent_table_name), K(ret));
      } else if (OB_ISNULL(child_table_schema)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("parent table schema is null", K(ret));
      }
    }
    if (OB_SUCC(ret)) {
      if (0 == parent_table_name.case_compare(table_name_) && 0 == database_name.case_compare(database_name_)) {
        parent_table_schema = child_table_schema;
        ObSEArray<ObString, 8>& parent_columns = arg.parent_columns_;
        ObSEArray<ObString, 8>& child_columns = arg.child_columns_;
        bool is_conflicted = false;
        for (int64_t i = 0; OB_SUCC(ret) && !is_conflicted && i < parent_columns.count(); ++i) {
          for (int64_t j = 0; OB_SUCC(ret) && !is_conflicted && j < child_columns.count(); ++j) {
            if (0 == parent_columns.at(i).compare(child_columns.at(j))) {
              is_conflicted = true;
              ret = OB_ERR_CANNOT_ADD_FOREIGN;
              LOG_WARN("cannot support that parent column is in child column list", K(ret));
            }
          }
        }
      } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
                     database_name,
                     parent_table_name,
                     false,
                     parent_table_schema))) {
        LOG_WARN("table is not exist", K(database_name), K(parent_table_name), K(ret));
      } else if (OB_ISNULL(parent_table_schema)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("parent table schema is null", K(ret));
      }
    }
    if (OB_SUCC(ret)) {
      if (!child_table_schema->is_user_table() || !parent_table_schema->is_user_table()) {
        ret = OB_ERR_CANNOT_ADD_FOREIGN;
        LOG_WARN("foreign key cannot be based on non-user table",
            K(ret),
            K(child_table_schema->is_user_table()),
            K(parent_table_schema->is_user_table()));
      } else {
        ObSEArray<ObString, 8>& child_columns = arg.child_columns_;
        ObSEArray<ObString, 8>& parent_columns = arg.parent_columns_;
        if (OB_FAIL(ObResolverUtils::check_foreign_key_columns_type(
                *child_table_schema, *parent_table_schema, child_columns, parent_columns, column))) {
          LOG_WARN("Failed to check_foreign_key_columns_type", K(ret));
        } else {
          bool is_matched = false;
          ObSArray<ObCreateIndexArg> index_arg_list;
          if (!is_alter_table) {
            if (parent_table_schema->get_table_id() == child_table_schema->get_table_id()) {
              index_arg_list.assign(create_table_stmt->get_index_arg_list());
            }
          }
          if (OB_FAIL(ObResolverUtils::foreign_key_column_match_uk_pk_column(
                  *parent_table_schema, *schema_checker_, parent_columns, index_arg_list, arg, is_matched))) {
            LOG_WARN("Failed to check reference columns in parent table");
          } else if (!is_matched) {
            if (share::is_mysql_mode()) {
              ret = OB_ERR_CANNOT_ADD_FOREIGN;
              LOG_WARN("reference columns aren't reference to pk or uk in parent table", K(ret));
            } else {  // oracle mode
              ret = OB_ERR_NO_MATCHING_UK_PK_FOR_COL_LIST;
              LOG_WARN("reference columns aren't reference to pk or uk in parent table", K(ret));
            }
          } else {
          }  // do-nothing
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::resolve_match_options(const ParseNode* match_options_node)
{
  int ret = OB_SUCCESS;

  if (OB_NOT_NULL(match_options_node)) {
    LOG_WARN("the function of match options on foreign key is not supported now.");
    if (T_FOREIGN_KEY_MATCH != match_options_node->type_) {
      ret = OB_INVALID_ARGUMENT;
      SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(match_options_node->type_));
    } else {
      switch (match_options_node->int32_values_[0]) {
        case T_SIMPLE:
          break;
        case T_FULL:
          break;
        case T_PARTIAL:
          break;
        default:
          ret = OB_INVALID_ARGUMENT;
          SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(match_options_node->int32_values_[0]));
          break;
      }
    }
  } else {
  }

  return ret;
}

int ObDDLResolver::create_fk_cons_name_automatically(ObString& foreign_key_name)
{
  int ret = OB_SUCCESS;
  char temp_str_buf[number::ObNumber::MAX_PRINTABLE_SIZE];
  ObString cons_name_str;
  bool is_exist = false;
  ObString tmp_table_name;

  if (table_name_.length() > OB_ORACLE_CONS_OR_IDX_CUTTED_NAME_LEN) {
    if (OB_FAIL(ob_sub_str(*allocator_, table_name_, 0, OB_ORACLE_CONS_OR_IDX_CUTTED_NAME_LEN - 1, tmp_table_name))) {
      SQL_RESV_LOG(WARN, "failed to cut table to 60 byte", K(ret), K(table_name_));
    }
  } else {
    tmp_table_name = table_name_;
  }
  if (OB_SUCC(ret)) {
    // use timestamp to ensure fk name unique
    if (snprintf(temp_str_buf,
            sizeof(temp_str_buf),
            "%.*s_OBFK_%ld",
            tmp_table_name.length(),
            tmp_table_name.ptr(),
            ObTimeUtility::current_time()) < 0) {
      ret = OB_SIZE_OVERFLOW;
      SQL_RESV_LOG(WARN, "failed to generate buffer for temp_str_buf", K(ret));
    } else if (OB_FAIL(ob_write_string(*allocator_, ObString::make_string(temp_str_buf), cons_name_str))) {
      SQL_RESV_LOG(WARN, "Can not malloc space for constraint name", K(ret));
    } else {
      int hash_ret = OB_HASH_NOT_EXIST;
      ObForeignKeyNameHashWrapper fk_key(foreign_key_name);
      foreign_key_name.assign_ptr(cons_name_str.ptr(), cons_name_str.length());
      // re-generate if fk name duplicated
      if (OB_HASH_EXIST == (hash_ret = current_foreign_key_name_set_.exist_refactored(fk_key))) {
        is_exist = true;
      }
      if (true == is_exist) {
        if (OB_FAIL(create_fk_cons_name_automatically(foreign_key_name))) {
          SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
        }
      } else {
        if (OB_FAIL(current_foreign_key_name_set_.set_refactored(fk_key))) {
          SQL_RESV_LOG(WARN, "set foreign key name to hash set failed", K(ret), K(foreign_key_name));
        }
      }
    }
  }

  return ret;
}

int ObDDLResolver::create_name_for_empty_partition(
    const bool is_subpartition, ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions)
{
  int ret = OB_SUCCESS;
  if (is_subpartition) {
    if (OB_FAIL(create_name_for_empty_partition(subpartitions))) {
      LOG_WARN("failed to create name for empty subpartitions", K(ret));
    }
  } else if (OB_FAIL(create_name_for_empty_partition(partitions))) {
    LOG_WARN("failed to create name for empty partitions", K(ret));
  }
  return ret;
}

int ObDDLResolver::store_part_key(const ObTableSchema& table_schema, obrpc::ObCreateIndexArg& index_arg)
{
  int ret = OB_SUCCESS;
  ObSEArray<uint64_t, 4> part_key_ids;
  ObSEArray<uint64_t, 4> index_rowkey_ids;
  const ObColumnSchemaV2* column = NULL;
  const bool check_column_exists = false;
  const bool is_hidden = true;
  if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2250) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("Create global index on no pk partitioned table not supported in old version", K(ret));
  } else if (OB_UNLIKELY(!table_schema.is_partitioned_table())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected partition level", K(ret), K(table_schema.get_part_level()));
  } else if (OB_FAIL(table_schema.get_partition_key_info().get_column_ids(part_key_ids))) {
    LOG_WARN("failed to get column ids", K(ret));
  } else if (PARTITION_LEVEL_TWO == table_schema.get_part_level() &&
             OB_FAIL(table_schema.get_subpartition_key_info().get_column_ids(part_key_ids))) {
    LOG_WARN("failed to get column ids", K(ret));
  }
  for (int64_t i = 0; OB_SUCC(ret) && i < index_arg.index_columns_.count(); ++i) {
    const ObColumnSortItem& column_item = index_arg.index_columns_.at(i);
    if (OB_FAIL(index_rowkey_ids.push_back(column_item.column_id_))) {
      LOG_WARN("failed to push back column id", K(ret));
    }
  }
  for (int64_t i = 0; OB_SUCC(ret) && i < part_key_ids.count(); ++i) {
    uint64_t column_id = part_key_ids.at(i);
    if (ObOptimizerUtil::find_item(index_rowkey_ids, column_id)) {
      // part key already in index rowkey, do nothing
    } else if (OB_ISNULL(column = table_schema.get_column_schema(column_id))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("get unexpected null", K(ret));
    } else if (OB_FAIL(add_storing_column(column->get_column_name_str(), check_column_exists, is_hidden))) {
      LOG_WARN("failed to add storing column", K(ret));
    }
  }
  LOG_TRACE("store part key", K(hidden_store_column_names_));
  return ret;
}

bool ObDDLResolver::is_column_exists(
    ObIArray<ObColumnNameWrapper>& sort_column_array, ObColumnNameWrapper& column_key, bool check_prefix_len)
{
  int bret = false;
  for (int64_t i = 0; !bret && i < sort_column_array.count(); ++i) {
    if (check_prefix_len) {
      if (sort_column_array.at(i).all_equal(column_key)) {
        bret = true;
      }
    } else if (sort_column_array.at(i).name_equal(column_key)) {
      bret = true;
    }
  }
  return bret;
}

int ObDDLResolver::get_enable_split_partition(const int64_t tenant_id, bool& enable_split_partition)
{
  int ret = OB_SUCCESS;
  enable_split_partition = false;
  if (OB_INVALID_TENANT_ID == tenant_id) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("tenant id is invalid", K(ret), K(tenant_id));
  } else {
    omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id));
    if (!tenant_config.is_valid()) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("failed to get tenant config", K(ret), K(tenant_id));
    } else {
      enable_split_partition = tenant_config->_enable_split_partition;
    }
  }
  return ret;
}

int ObDDLResolver::resolve_partition_name(
    ParseNode* partition_name_node, ObString& partition_name, ObBasePartition& partition)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(partition_name_node) || OB_ISNULL(partition_name_node->children_[NAMENODE])) {
    if (is_oracle_mode()) {
      partition.set_is_empty_partition_name(true);
    } else {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("partition expr list node is null", K(ret));
    }
  } else {
    ParseNode* name_node = partition_name_node->children_[NAMENODE];
    partition_name.assign_ptr(name_node->str_value_, static_cast<int32_t>(name_node->str_len_));
    if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
      ret = OB_ERR_TOO_LONG_IDENT;
    } else if (OB_FAIL(partition.set_part_name(partition_name))) {
      LOG_WARN("failed to set part name", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::resolve_partition_part_id(ParseNode* part_id_node, const ObDDLStmt* stmt,
    const int64_t max_used_part_id, const int64_t partition_num, const int64_t partition_element_idx, int64_t& part_id,
    bool& is_spec_part_id)
{
  int ret = OB_SUCCESS;
  is_spec_part_id = false;
  if (OB_ISNULL(part_id_node)) {
    part_id =
        max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + partition_element_idx : partition_element_idx;
  } else {
    part_id = static_cast<int32_t>(part_id_node->children_[0]->value_);
    is_spec_part_id = true;
    bool is_valid = false;
    if (OB_FAIL(check_partid_valid(stmt, part_id, max_used_part_id, is_valid))) {
      LOG_WARN("failed to check partid valid", K(ret));
    } else if (!is_valid) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("part id not valid", K(ret), K(part_id));
    }
  }
  if (OB_SUCC(ret) && part_id < 0) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid part_id", K(ret), K(part_id));
  }
  return ret;
}

// resolve hash/key partition basic infos, include:
// 1. partition function type
// 2. partition function expr name
// 3. partition keys (set in this function)
int ObDDLResolver::resolve_hash_or_key_partition_basic_infos(ParseNode* node, bool is_subpartition,
    ObTableSchema& table_schema, ObPartitionFuncType& part_func_type, ObString& func_expr_name, ObSqlString& part_str)
{
  int ret = OB_SUCCESS;
  ParseNode* partition_fun_node = NULL;
  part_func_type = PARTITION_FUNC_TYPE_HASH;
  const share::schema::ObTablegroupSchema* tablegroup_schema = NULL;
  if (OB_ISNULL(node) || OB_ISNULL(node->children_) ||
      OB_ISNULL(partition_fun_node = node->children_[HASH_FUN_EXPR_NODE]) || OB_ISNULL(schema_checker_) ||
      OB_ISNULL(session_info_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(partition_fun_node), K(schema_checker_), K(session_info_));
  } else if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_3000 && !table_schema.get_tablegroup_name().empty() &&
             OB_FAIL(schema_checker_->get_tablegroup_schema(
                 session_info_->get_effective_tenant_id(), table_schema.get_tablegroup_name(), tablegroup_schema))) {
    LOG_WARN("fail to get tablegroup schema", K(ret), K(table_schema.get_tablegroup_name()));
  } else {
    if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_3000) {
      part_func_type = T_HASH_PARTITION == node->type_ ? share::schema::PARTITION_FUNC_TYPE_HASH
                                                       : share::schema::PARTITION_FUNC_TYPE_KEY_V2;
    } else {
      part_func_type = T_HASH_PARTITION == node->type_ ? share::schema::PARTITION_FUNC_TYPE_HASH_V2
                                                       : share::schema::PARTITION_FUNC_TYPE_KEY_V3;
    }

    // compatible with old version
    if (tablegroup_schema != NULL) {
      if (tablegroup_schema->get_part_level() >= table_schema.get_part_level()) {
        const share::schema::ObPartitionOption& tablegroup_part =
            !is_subpartition ? tablegroup_schema->get_part_option() : tablegroup_schema->get_sub_part_option();
        if (part_func_type == share::schema::PARTITION_FUNC_TYPE_HASH_V2 &&
            tablegroup_part.get_part_func_type() == share::schema::PARTITION_FUNC_TYPE_HASH) {
          part_func_type = share::schema::PARTITION_FUNC_TYPE_HASH;
        } else if (part_func_type == share::schema::PARTITION_FUNC_TYPE_KEY_V3 &&
                   tablegroup_part.get_part_func_type() == share::schema::PARTITION_FUNC_TYPE_KEY_V2) {
          part_func_type = share::schema::PARTITION_FUNC_TYPE_KEY_V2;
        } else { /*do nothing */
        }
      }
    }
  }

  if (OB_SUCC(ret)) {
    if (NULL == partition_fun_node->children_[1]) {  // partition by key()
      if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_3000) {
        part_func_type = share::schema::PARTITION_FUNC_TYPE_KEY_IMPLICIT;
      } else {
        part_func_type = share::schema::PARTITION_FUNC_TYPE_KEY_IMPLICIT_V2;
      }
      if (OB_FAIL(build_partition_key_info(
              table_schema, is_subpartition, part_func_type == share::schema::PARTITION_FUNC_TYPE_KEY_IMPLICIT_V2))) {
        LOG_WARN("failed to build partition key info", K(ret), K(table_schema), K(is_subpartition));
      }
    } else {
      ObSEArray<ObRawExpr*, 4> dummy_part_func_exprs;
      ObSEArray<ObString, 4> partition_keys;
      if (OB_FAIL(resolve_part_func(
              params_, partition_fun_node, part_func_type, table_schema, dummy_part_func_exprs, partition_keys))) {
        LOG_WARN("failed to resolve part func", K(ret));
      } else if (OB_FAIL(set_partition_keys(table_schema, partition_keys, is_subpartition))) {
        LOG_WARN("failed to set partition keys", K(ret), K(table_schema), K(is_subpartition));
      }
    }
  }

  if (OB_SUCC(ret)) {
    func_expr_name.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
    if (!share::is_oracle_mode()) {
      // TODO(:maybe not valid here, if expr include table name or databae name)
      ObCharset::casedn(CS_TYPE_UTF8MB4_GENERAL_CI, func_expr_name);
    }

    // TODO now, just for compat inner_table process.
    if (is_inner_table(table_id_)) {
      if (OB_FAIL(get_part_str_with_type(part_func_type, func_expr_name, part_str))) {
        SQL_RESV_LOG(WARN, "Failed to get part str with type", K(ret));
      } else if (FALSE_IT(func_expr_name = part_str.string())) {
      } else if (PARTITION_FUNC_TYPE_KEY_V2 == part_func_type || PARTITION_FUNC_TYPE_KEY_V3 == part_func_type) {
        part_func_type = PARTITION_FUNC_TYPE_KEY;
      }
    }
  }
  return ret;
}

// resolve range partition basic infos, include:
// 1. partition function type
// 2. partition function expr name
// 3. partition function exprs
// 4. partition keys (set in this function)
int ObDDLResolver::resolve_range_partition_basic_infos(ParseNode* node, bool is_subpartition,
    ObTableSchema& table_schema, ObPartitionFuncType& part_func_type, ObString& func_expr_name,
    ObIArray<ObRawExpr*>& part_func_exprs)
{
  int ret = OB_SUCCESS;
  ParseNode* partition_fun_node = NULL;
  part_func_type = PARTITION_FUNC_TYPE_RANGE;
  ObSEArray<ObString, 4> partition_keys;
  if (OB_ISNULL(node) || OB_ISNULL(partition_fun_node = node->children_[RANGE_FUN_EXPR_NODE])) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(partition_fun_node));
  } else if (T_RANGE_COLUMNS_PARTITION == node->type_) {
    part_func_type = PARTITION_FUNC_TYPE_RANGE_COLUMNS;
  }

  if (OB_SUCC(ret)) {
    func_expr_name.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
    if (OB_FAIL(resolve_part_func(
            params_, partition_fun_node, part_func_type, table_schema, part_func_exprs, partition_keys))) {
      LOG_WARN("resolve part func failed", K(ret));
    } else if (OB_FAIL(set_partition_keys(table_schema, partition_keys, is_subpartition))) {
      LOG_WARN("Failed to set partition keys", K(ret), K(table_schema), K(is_subpartition));
    }
  }
  return ret;
}

// resolve list partition basic infos, include:
// 1. partition function type
// 2. partition function expr name
// 3. partition function exprs
// 4. partition keys (set in this function)
int ObDDLResolver::resolve_list_partition_basic_infos(ParseNode* node, bool is_subpartition,
    ObTableSchema& table_schema, ObPartitionFuncType& part_func_type, ObString& func_expr_name,
    ObIArray<ObRawExpr*>& part_func_exprs)
{
  int ret = OB_SUCCESS;
  ParseNode* partition_fun_node = NULL;
  part_func_type = PARTITION_FUNC_TYPE_LIST;
  ObSEArray<ObString, 4> partition_keys;
  if (OB_ISNULL(node) || OB_ISNULL(partition_fun_node = node->children_[LIST_FUN_EXPR_NODE])) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(partition_fun_node));
  } else if (T_LIST_COLUMNS_PARTITION == node->type_) {
    part_func_type = PARTITION_FUNC_TYPE_LIST_COLUMNS;
  }

  if (OB_SUCC(ret)) {
    func_expr_name.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
    if (OB_FAIL(resolve_part_func(
            params_, partition_fun_node, part_func_type, table_schema, part_func_exprs, partition_keys))) {
      LOG_WARN("resolve part func failed", K(ret));
    } else if (OB_FAIL(set_partition_keys(table_schema, partition_keys, is_subpartition))) {
      LOG_WARN("Failed to set partition keys", K(ret), K(table_schema), K(is_subpartition));
    }
  }
  return ret;
}

int ObDDLResolver::resolve_partition_node(ObPartitionedStmt* stmt, ParseNode* part_node, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  if (is_hash_type_partition(part_node->type_)) {
    ret = resolve_partition_hash_or_key(stmt, part_node, false, table_schema);
  } else if (is_range_type_partition(part_node->type_)) {
    ret = resolve_partition_range(stmt, part_node, false, table_schema);
  } else if (is_list_type_partition(part_node->type_)) {
    ret = resolve_partition_list(stmt, part_node, false, table_schema);
  } else {
    ret = OB_INVALID_ARGUMENT;
    SQL_RESV_LOG(WARN, "node type is invalid.", K(ret), K(part_node->type_));
  }

  if (OB_SUCC(ret) && !common::is_virtual_table(table_id_)) {
    if (table_schema.get_all_part_num() >
        (lib::is_oracle_mode() ? common::OB_MAX_PARTITION_NUM_ORACLE : common::OB_MAX_PARTITION_NUM_MYSQL)) {
      ret = common::OB_TOO_MANY_PARTITIONS_ERROR;
    }
  }

  if (OB_SUCC(ret)) {
    if (OB_FAIL(check_and_set_partition_names(stmt, table_schema))) {
      LOG_WARN("failed to check and set partition names", K(ret));
    }
  }

  return ret;
}

int ObDDLResolver::resolve_subpartition_option(
    ObPartitionedStmt* stmt, ParseNode* subpart_node, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  if (is_hash_type_partition(subpart_node->type_)) {
    if (OB_FAIL(resolve_partition_hash_or_key(stmt, subpart_node, true, table_schema))) {
      SQL_RESV_LOG(WARN, "failed to resolve partition hash or key", K(ret));
    }
  } else if (is_range_type_partition(subpart_node->type_)) {
    if (OB_FAIL(resolve_partition_range(stmt, subpart_node, true, table_schema))) {
      SQL_RESV_LOG(WARN, "failed to resolve partition range", K(ret));
    }
  } else if (is_list_type_partition(subpart_node->type_)) {
    if (OB_FAIL(resolve_partition_list(stmt, subpart_node, true, table_schema))) {
      SQL_RESV_LOG(WARN, "failed to resolve partition list", K(ret));
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "get unexpected subpartition type", K(ret), K(subpart_node->type_));
  }
  return ret;
}

int ObDDLResolver::resolve_individual_subpartition(ObPartitionedStmt* stmt, ParseNode* part_node,
    ParseNode* partition_list_node, ParseNode* subpart_node, share::schema::ObTableSchema& table_schema,
    bool& force_template)
{
  int ret = OB_SUCCESS;
  share::schema::ObPartitionFuncType partition_func_type = share::schema::PARTITION_FUNC_TYPE_HASH;
  ObString func_expr_name;
  common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
  table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
  force_template = false;
  ObSqlString part_str;

  if (OB_ISNULL(stmt) || OB_ISNULL(part_node) || OB_ISNULL(subpart_node)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "get unexpected null", K(ret), K(stmt), K(part_node), K(subpart_node));
  } else if (is_range_type_partition(subpart_node->type_)) {
    // range subpartition
    if (OB_FAIL(resolve_range_partition_basic_infos(
            subpart_node, true, table_schema, partition_func_type, func_expr_name, part_func_exprs))) {
      SQL_RESV_LOG(WARN, "failed to resolve range partition basic infos", K(ret));
    } else if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
      SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
    }
  } else if (is_list_type_partition(subpart_node->type_)) {
    // list subpartition
    if (OB_FAIL(resolve_list_partition_basic_infos(
            subpart_node, true, table_schema, partition_func_type, func_expr_name, part_func_exprs))) {
      SQL_RESV_LOG(WARN, "failed to resolve list partition basic infos", K(ret));
    } else if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
      SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
    }
  } else if (is_hash_type_partition(subpart_node->type_)) {
    /**
     *  create table t1 (c1 int, c2 int) partition by range (c1)
     *  subpartition by hash (c2) subpartitions 3
     *  (
     *    partition p0 values less than (100),
     *    partition p1 values less than (200)
     *  );
     *  create table t2 (c1 int, c2 int) partition by range (c1)
     *  subpartition by hash (c2) subpartitions 3
     *  (
     *    partition p0 values less than (100)
     *    (
     *      subpartition p0_h1,
     *      subpartition p0_h2
     *    ),
     *    partition p1 values less than (200)
     *  );
     */
    if (NULL != partition_list_node) {
      bool has_def_subpart = false;
      for (int64_t i = 0; OB_SUCC(ret) && !has_def_subpart && i < partition_list_node->num_child_; ++i) {
        if (OB_ISNULL(partition_list_node->children_[i])) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("get unexpected null", K(ret));
        } else if (NULL != partition_list_node->children_[i]->children_[ELEMENT_SUBPARTITION_NODE]) {
          has_def_subpart = true;
        }
      }
      if (OB_SUCC(ret) && !has_def_subpart) {
        force_template = true;
      }
    } else {
      // auto set templated secondary partitions
      force_template = true;
    }

    if (OB_SUCC(ret) && !force_template) {
      if (OB_FAIL(resolve_hash_or_key_partition_basic_infos(
              subpart_node, true, table_schema, partition_func_type, func_expr_name, part_str))) {
        SQL_RESV_LOG(WARN, "failed to resolve hash or key parititon basic infos", K(ret));
      } else if (NULL != subpart_node->children_[HASH_PARTITION_NUM_NODE]) {
        hash_subpart_num_ = subpart_node->children_[HASH_PARTITION_NUM_NODE]->value_;
        if (hash_subpart_num_ <= 0) {
          ret = common::OB_NO_PARTS_ERROR;
          LOG_USER_ERROR(OB_NO_PARTS_ERROR);
        }
      } else {
        hash_subpart_num_ = 1;
      }
    }
  }

  if (OB_SUCC(ret) && !force_template) {
    table_schema.get_sub_part_option().set_part_func_type(partition_func_type);
    if (OB_FAIL(table_schema.get_sub_part_option().set_part_expr(func_expr_name))) {
      SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::resolve_subpartition_elements(
    ObPartitionedStmt* stmt, ParseNode* node, ObTableSchema& table_schema, ObPartition* partition, bool in_tablegroup)
{
  int ret = OB_SUCCESS;
  ObPartitionFuncType subpart_type = table_schema.get_sub_part_option().get_part_func_type();
  int64_t max_used_subpart_id = -1;
  if (OB_ISNULL(partition)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret));
  } else if (FALSE_IT(max_used_subpart_id = partition->get_max_used_sub_part_id())) {
  } else if (OB_ISNULL(node)) {
    if (!is_hash_like_part(subpart_type)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("get unexpected null", K(ret));
    } else if (hash_subpart_num_ < 1) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("default subpart num not specified", K(ret), K(hash_subpart_num_));
    } else if (OB_FAIL(
                   generate_default_hash_subpart(hash_subpart_num_, max_used_subpart_id, table_schema, partition))) {
      LOG_WARN("failed to generate default hash subpart", K(ret));
    }
  } else if ((is_hash_like_part(subpart_type) && node->type_ != T_HASH_SUBPARTITION_LIST) ||
             (is_range_part(subpart_type) && node->type_ != T_RANGE_SUBPARTITION_LIST) ||
             (is_list_part(subpart_type) && node->type_ != T_LIST_SUBPARTITION_LIST)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("subpartition define is not match declare", K(ret), K(subpart_type), K(node->type_));
  } else if (T_HASH_SUBPARTITION_LIST == node->type_) {
    if (OB_FAIL(resolve_hash_subpartition_elements(stmt, node, table_schema, partition, max_used_subpart_id))) {
      LOG_WARN("failed to resolve hash subpartition elements", K(ret));
    }
  } else if (T_RANGE_SUBPARTITION_LIST == node->type_) {
    ObDDLStmt::array_t range_value_exprs;
    if (OB_FAIL(resolve_range_subpartition_elements(stmt,
            node,
            table_schema,
            partition,
            subpart_type,
            stmt->get_subpart_fun_exprs(),
            range_value_exprs,
            max_used_subpart_id,
            in_tablegroup))) {
      LOG_WARN("failed to resolve hash subpartition elements", K(ret));
    } else if (OB_FAIL(stmt->get_individual_subpart_values_exprs().push_back(range_value_exprs))) {
      LOG_WARN("failed to push back range value exprs");
    }
  } else if (T_LIST_SUBPARTITION_LIST == node->type_) {
    ObDDLStmt::array_t list_value_exprs;
    if (OB_FAIL(resolve_list_subpartition_elements(stmt,
            node,
            table_schema,
            partition,
            subpart_type,
            stmt->get_subpart_fun_exprs(),
            list_value_exprs,
            max_used_subpart_id,
            in_tablegroup))) {
      LOG_WARN("failed to resolve hash subpartition elements", K(ret));
    } else if (OB_FAIL(stmt->get_individual_subpart_values_exprs().push_back(list_value_exprs))) {
      LOG_WARN("failed to push back range value exprs");
    }
  }

  if (OB_SUCC(ret)) {
    if (OB_FAIL(check_max_used_subpart_id_valid(table_schema, *partition, max_used_subpart_id))) {
      LOG_WARN("faield to check max used subpart id", K(ret));
    } else {
      partition->set_max_used_sub_part_id(max_used_subpart_id);
    }
  }
  return ret;
}

int ObDDLResolver::resolve_partition_hash_or_key(
    ObPartitionedStmt* stmt, ParseNode* node, const bool is_subpartition, ObTableSchema& table_schema)
{
  int ret = common::OB_SUCCESS;
  ObString partition_expr;
  ObPartitionFuncType partition_func_type = PARTITION_FUNC_TYPE_HASH;
  int64_t partition_num = 0;
  ObPartitionOption* partition_option = NULL;

  if (OB_ISNULL(node) || OB_ISNULL(node->children_) || !is_hash_type_partition(node->type_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected node", K(ret), K(node));
  } else if (is_subpartition && NULL != node->children_[HASH_SUBPARTITIOPPN_NODE]) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("subpartition cannot has another subpartition", K(ret));
  } else if (is_subpartition) {
    partition_option = &(table_schema.get_sub_part_option());
    table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
  } else {
    partition_option = &(table_schema.get_part_option());
    table_schema.set_part_level(share::schema::PARTITION_LEVEL_ONE);
  }

  if (OB_SUCC(ret)) {
    if (NULL != node->children_[HASH_SUBPARTITIOPPN_NODE]) {
      bool force_template = false;
      if (NULL != node->children_[HASH_SUBPARTITIOPPN_NODE]->children_[HASH_TEMPLATE_MARK]) {
        table_schema.set_is_sub_part_template(true);
      } else if (OB_FAIL(resolve_individual_subpartition(stmt,
                     node,
                     node->children_[HASH_PARTITION_LIST_NODE],
                     node->children_[HASH_SUBPARTITIOPPN_NODE],
                     table_schema,
                     force_template))) {
        SQL_RESV_LOG(WARN, "failed to resolve individual subpartition", K(ret));
      } else if (force_template) {
        table_schema.set_is_sub_part_template(true);
      } else {
        table_schema.set_is_sub_part_template(false);
      }
    }
  }

  // 1. resolve partition type, partition keys, partition expr
  if (OB_SUCC(ret)) {
    ObSqlString part_str;
    if (OB_FAIL(resolve_hash_or_key_partition_basic_infos(
            node, is_subpartition, table_schema, partition_func_type, partition_expr, part_str))) {
      SQL_RESV_LOG(WARN, "failed to resolve hash or key parititon basic infos", K(ret));
    } else {
      partition_option->set_part_func_type(partition_func_type);
      if (OB_FAIL(partition_option->set_part_expr(partition_expr))) {
        SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
      }
    }
  }

  // 2. process part defination
  if (OB_SUCC(ret)) {
    if (NULL != node->children_[HASH_PARTITION_NUM_NODE]) {
      partition_num = node->children_[HASH_PARTITION_NUM_NODE]->value_;
    } else if (NULL == node->children_[HASH_PARTITION_LIST_NODE]) {
      partition_num = 1;
    } else {
      partition_num = 1;
    }

    if (NULL != node->children_[HASH_PARTITION_NUM_NODE] && NULL != node->children_[HASH_PARTITION_LIST_NODE]) {
      if (is_oracle_mode()) {
        ret = OB_ERR_SPECIFIY_PARTITION_DESCRIPTION;
      } else if (partition_num != node->children_[HASH_PARTITION_LIST_NODE]->num_child_) {
        ret = OB_ERR_PARSE_PARTITION_RANGE;
      }
    }

    if (OB_FAIL(ret)) {
    } else if (partition_num <= 0) {
      ret = common::OB_NO_PARTS_ERROR;
      LOG_USER_ERROR(OB_NO_PARTS_ERROR);
    } else if (!common::is_virtual_table(table_id_) &&
               partition_num >
                   (lib::is_oracle_mode() ? common::OB_MAX_PARTITION_NUM_ORACLE : common::OB_MAX_PARTITION_NUM_MYSQL)) {
      ret = common::OB_TOO_MANY_PARTITIONS_ERROR;
    } else if (is_subpartition) {
      if (NULL != node->children_[HASH_PARTITION_LIST_NODE]) {
        if (OB_FAIL(resolve_hash_subpartition_elements(
                stmt, node->children_[HASH_PARTITION_LIST_NODE], table_schema, NULL /* dummy partition*/))) {
          SQL_RESV_LOG(WARN, "failed to resolve hash subpartition elements", K(ret));
        }
      } else {
        if (OB_FAIL(generate_default_hash_subpart(partition_num,
                -1,  // max_used_supart_id
                table_schema,
                NULL))) {  // dummy partition
          LOG_WARN("failed to generate default hash part", K(ret));
        }
      }
    } else {
      if (NULL != node->children_[HASH_PARTITION_LIST_NODE]) {
        if (OB_FAIL(resolve_hash_partition_elements(
                stmt, node->children_[HASH_PARTITION_LIST_NODE], table_schema, max_used_part_id_))) {
          LOG_WARN("failed to resolve hash partition elements", K(ret));
        }
      } else {
        if (OB_FAIL(generate_default_hash_part(partition_num, max_used_part_id_, table_schema))) {
          LOG_WARN("failed to generate default hash part", K(ret));
        }
        if (!table_schema.is_sub_part_template()) {
          if (table_schema.is_hash_like_subpart()) {
            // partition by hash(c1) subpartition by hash(c2) subpartitions 3 partitions 3
            for (int64_t i = 0; OB_SUCC(ret) && i < table_schema.get_first_part_num(); ++i) {
              if (OB_FAIL(resolve_subpartition_elements(stmt,
                      NULL,  // dummy node
                      table_schema,
                      table_schema.get_part_array()[i],
                      false))) {
                LOG_WARN("failed to resolve subpartition elements", K(ret));
              }
            }
          } else {
            ret = OB_INVALID_ARGUMENT;
            LOG_WARN("invalid partition define", K(ret));
          }
        }
      }
    }
  }

  if (OB_SUCC(ret)) {
    if (NULL != node->children_[HASH_SUBPARTITIOPPN_NODE] && table_schema.is_sub_part_template()) {
      if (OB_FAIL(resolve_subpartition_option(stmt, node->children_[HASH_SUBPARTITIOPPN_NODE], table_schema))) {
        SQL_RESV_LOG(WARN, "failed to resolve subpartition", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_partition_range(
    ObPartitionedStmt* stmt, ParseNode* node, const bool is_subpartition, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  ObString func_expr_name;
  int64_t partition_num = 0;
  share::schema::ObPartitionFuncType part_func_type = share::schema::PARTITION_FUNC_TYPE_RANGE;
  common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
  common::ObSEArray<ObRawExpr*, 8> range_values_exprs;
  share::schema::ObPartitionOption* partition_option = NULL;

  if (OB_ISNULL(stmt) || OB_ISNULL(node) || OB_ISNULL(node->children_) ||
      OB_ISNULL(node->children_[RANGE_ELEMENTS_NODE])) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "get unexpected null", K(ret), K(stmt), K(node));
  } else if (!is_range_type_partition(node->type_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "get unexpected partition type", K(ret), K(node->type_));
  } else if (is_subpartition) {
    partition_option = &(table_schema.get_sub_part_option());
    table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
  } else {
    partition_option = &(table_schema.get_part_option());
    table_schema.set_part_level(share::schema::PARTITION_LEVEL_ONE);
  }

  if (OB_SUCC(ret)) {
    if (NULL != node->children_[RANGE_SUBPARTITIOPPN_NODE]) {
      bool force_template = false;
      if (NULL != node->children_[RANGE_SUBPARTITIOPPN_NODE]->children_[RANGE_TEMPLATE_MARK]) {
        table_schema.set_is_sub_part_template(true);
      } else if (OB_FAIL(resolve_individual_subpartition(stmt,
                     node,
                     node->children_[RANGE_ELEMENTS_NODE],
                     node->children_[RANGE_SUBPARTITIOPPN_NODE],
                     table_schema,
                     force_template))) {
        SQL_RESV_LOG(WARN, "failed to resolve individual subpartition", K(ret));
      } else if (force_template) {
        table_schema.set_is_sub_part_template(true);
      } else {
        table_schema.set_is_sub_part_template(false);
      }
    }
  }

  // 1. resolve partition type, partition keys, partition expr
  if (OB_SUCC(ret)) {
    if (OB_FAIL(resolve_range_partition_basic_infos(
            node, is_subpartition, table_schema, part_func_type, func_expr_name, part_func_exprs))) {
      SQL_RESV_LOG(WARN, "failed to resolve range partition basic infos", K(ret));
    } else if (OB_FAIL(partition_option->set_part_expr(func_expr_name))) {
      SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
    } else {
      partition_option->set_part_func_type(part_func_type);
    }
  }

  // 2. resolve range partition define
  if (OB_SUCC(ret)) {
    if (NULL != node->children_[RANGE_PARTITION_NUM_NODE]) {
      partition_num = node->children_[RANGE_PARTITION_NUM_NODE]->value_;
      if (partition_num != node->children_[RANGE_ELEMENTS_NODE]->num_child_) {
        ret = OB_ERR_PARSE_PARTITION_RANGE;
      }
    } else {
      partition_num = node->children_[RANGE_ELEMENTS_NODE]->num_child_;
    }
    partition_option->set_part_num(partition_num);
    if (OB_SUCC(ret)) {
      if (OB_FAIL(check_partition_name_duplicate(node->children_[RANGE_ELEMENTS_NODE], lib::is_oracle_mode()))) {
        SQL_RESV_LOG(WARN, "duplicate partition name", K(ret));
      } else if (is_subpartition) {
        if (OB_FAIL(resolve_range_subpartition_elements(stmt,
                node->children_[RANGE_ELEMENTS_NODE],
                table_schema,
                NULL,  // dummy partition
                part_func_type,
                part_func_exprs,
                range_values_exprs,
                -1 /* max_used_subpart_id */))) {
          SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
        }
      } else {
        if (OB_FAIL(resolve_range_partition_elements(stmt,
                node->children_[RANGE_ELEMENTS_NODE],
                table_schema,
                part_func_type,
                part_func_exprs,
                range_values_exprs,
                max_used_part_id_))) {
          SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
        }
      }
    }
  }

  if (OB_SUCC(ret)) {
    if (NULL != node->children_[RANGE_SUBPARTITIOPPN_NODE] && table_schema.is_sub_part_template()) {
      if (OB_FAIL(resolve_subpartition_option(stmt, node->children_[RANGE_SUBPARTITIOPPN_NODE], table_schema))) {
        SQL_RESV_LOG(WARN, "failed to resolve subpartition", K(ret));
      }
    }
  }

  if (OB_SUCC(ret)) {
    if (is_subpartition) {
      if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
      } else if (OB_FAIL(stmt->get_template_subpart_values_exprs().assign(range_values_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
      }
    } else {
      if (OB_FAIL(stmt->get_part_fun_exprs().assign(part_func_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
      } else if (OB_FAIL(stmt->get_part_values_exprs().assign(range_values_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
      }
    }
    SQL_RESV_LOG(DEBUG, "succ to resolve_partition_range", KPC(stmt), K(part_func_exprs), K(range_values_exprs));
  }
  return ret;
}

int ObDDLResolver::resolve_partition_list(
    ObPartitionedStmt* stmt, ParseNode* node, const bool is_subpartition, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  ObString func_expr_name;
  ObPartitionOption* partition_option = NULL;
  int64_t partition_num = 0;
  ObPartitionFuncType part_func_type = PARTITION_FUNC_TYPE_LIST;
  common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
  ObDDLStmt::array_t list_values_exprs;

  if (OB_ISNULL(stmt) || OB_ISNULL(node) || OB_ISNULL(node->children_) ||
      OB_ISNULL(node->children_[LIST_ELEMENTS_NODE])) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "get unexpected null", K(ret), K(stmt), K(node));
  } else if (!is_list_type_partition(node->type_)) {
    ret = OB_ERR_UNEXPECTED;
    SQL_RESV_LOG(WARN, "get unexpected partition type", K(ret), K(node->type_));
  } else if (is_subpartition) {
    partition_option = &(table_schema.get_sub_part_option());
    table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
  } else {
    partition_option = &(table_schema.get_part_option());
    table_schema.set_part_level(share::schema::PARTITION_LEVEL_ONE);
  }

  if (OB_SUCC(ret)) {
    if (NULL != node->children_[LIST_SUBPARTITIOPPN_NODE]) {
      bool force_template = false;
      if (NULL != node->children_[LIST_SUBPARTITIOPPN_NODE]->children_[LIST_TEMPLATE_MARK]) {
        table_schema.set_is_sub_part_template(true);
      } else if (OB_FAIL(resolve_individual_subpartition(stmt,
                     node,
                     node->children_[LIST_ELEMENTS_NODE],
                     node->children_[LIST_SUBPARTITIOPPN_NODE],
                     table_schema,
                     force_template))) {
        SQL_RESV_LOG(WARN, "failed to resolve individual subpartition", K(ret));
      } else if (force_template) {
        table_schema.set_is_sub_part_template(true);
      } else {
        table_schema.set_is_sub_part_template(false);
      }
    }
  }
  // 1. resolve partition type, partition keys, partition expr
  if (OB_SUCC(ret)) {
    if (OB_FAIL(resolve_list_partition_basic_infos(
            node, is_subpartition, table_schema, part_func_type, func_expr_name, part_func_exprs))) {
      SQL_RESV_LOG(WARN, "failed to resolve range partition basic infos", K(ret));
    } else if (OB_FAIL(partition_option->set_part_expr(func_expr_name))) {
      SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
    } else {
      partition_option->set_part_func_type(part_func_type);
    }
  }

  if (OB_SUCC(ret)) {
    if (!OB_ISNULL(node->children_[LIST_PARTITION_NUM_NODE])) {
      partition_num = node->children_[LIST_PARTITION_NUM_NODE]->value_;
      if (partition_num != node->children_[LIST_ELEMENTS_NODE]->num_child_) {
        ret = common::OB_ERR_PARSE_PARTITION_LIST;
      }
    } else {
      partition_num = node->children_[LIST_ELEMENTS_NODE]->num_child_;
    }
    partition_option->set_part_num(partition_num);
    if (OB_SUCC(ret)) {
      if (OB_FAIL(check_partition_name_duplicate(node->children_[LIST_ELEMENTS_NODE], lib::is_oracle_mode()))) {
        SQL_RESV_LOG(WARN, "duplicate partition name", K(ret));
      } else if (is_subpartition) {
        if (OB_FAIL(resolve_list_subpartition_elements(stmt,
                node->children_[LIST_ELEMENTS_NODE],
                table_schema,
                NULL,  // dummy partition
                part_func_type,
                part_func_exprs,
                list_values_exprs,
                -1))) {
          SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
        }
      } else {
        if (OB_FAIL(resolve_list_partition_elements(stmt,
                node->children_[LIST_ELEMENTS_NODE],
                table_schema,
                part_func_type,
                part_func_exprs,
                list_values_exprs,
                max_used_part_id_))) {
          SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
        }
      }
    }
  }

  if (OB_SUCC(ret)) {
    if (NULL != node->children_[LIST_SUBPARTITIOPPN_NODE] && table_schema.is_sub_part_template()) {
      if (OB_FAIL(resolve_subpartition_option(stmt, node->children_[LIST_SUBPARTITIOPPN_NODE], table_schema))) {
        SQL_RESV_LOG(WARN, "failed to resolve subpartition", K(ret));
      }
    }
  }

  if (OB_SUCC(ret)) {
    if (is_subpartition) {
      if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
      } else if (OB_FAIL(stmt->get_template_subpart_values_exprs().assign(list_values_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
      }
    } else {
      if (OB_FAIL(stmt->get_part_fun_exprs().assign(part_func_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
      } else if (OB_FAIL(stmt->get_part_values_exprs().assign(list_values_exprs))) {
        SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
      }
    }
    SQL_RESV_LOG(DEBUG, "succ to resolve_partition_list", KPC(stmt), K(part_func_exprs), K(list_values_exprs));
  }
  return ret;
}

int ObDDLResolver::resolve_hash_partition_elements(
    ObPartitionedStmt* stmt, ParseNode* node, ObTableSchema& table_schema, int64_t max_used_part_id)
{
  int ret = OB_SUCCESS;
  ParseNode* element_node = NULL;
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(stmt));
  } else if (max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ObPartition partition;
    bool init_specified = false;
    // ignore alter_table with part_id
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
      partition.reset();
      ObString partition_name;
      int64_t part_id = OB_INVALID_ID;
      bool current_spec = false;
      // 1. check partition name
      if (OB_ISNULL(element_node = node->children_[i])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(element_node));
      } else if (OB_FAIL(
                     resolve_partition_name(element_node->children_[PARTITION_NAME_NODE], partition_name, partition))) {
        LOG_WARN("failed to resolve partition name", K(ret));
      } else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
                     stmt,
                     max_used_part_id,
                     partition_num,
                     i,
                     part_id,
                     current_spec))) {
        LOG_WARN("failed to resolve partition part id", K(ret));
      } else {
        // all partition should both specified part id or not
        if (0 == i) {
          init_specified = current_spec;
        } else if (current_spec != init_specified) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
        }
      }
      // add hash partition elements to table schema
      if (OB_SUCC(ret)) {
        partition.set_part_id(part_id);
        partition.set_part_idx(i);
        if (OB_FAIL(table_schema.check_part_id(partition))) {
          LOG_WARN("failed to check part id", K(ret));
        } else if (OB_FAIL(table_schema.add_partition(partition))) {
          LOG_WARN("failed to add partition", K(ret));
        } else if (table_schema.is_sub_part_template() &&
                   OB_NOT_NULL(element_node->children_[ELEMENT_SUBPARTITION_NODE])) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("individual subpartition with sub part template", K(ret));
        } else if (!table_schema.is_sub_part_template()) {
          // resolve non template
          ObPartition* cur_partition = table_schema.get_part_array()[i];
          if (OB_ISNULL(cur_partition)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("get unexpected null", K(ret));
          } else if (OB_FAIL(resolve_subpartition_elements(stmt,
                         element_node->children_[ELEMENT_SUBPARTITION_NODE],
                         table_schema,
                         cur_partition,
                         false))) {
            LOG_WARN("failed to resolve subpartition elements", K(ret));
          }
        }
      }
    }
    if (OB_SUCC(ret)) {
      table_schema.get_part_option().set_part_num(partition_num);
    }
  }
  return ret;
}

int ObDDLResolver::resolve_hash_subpartition_elements(ObPartitionedStmt* stmt, ParseNode* node,
    ObTableSchema& table_schema, ObPartition* partition, int64_t max_used_subpart_id)
{
  int ret = OB_SUCCESS;
  ParseNode* element_node = NULL;
  const bool is_template = table_schema.is_sub_part_template();
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(stmt));
  } else if (!is_template && OB_ISNULL(partition)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("partition is null while not sub part template", K(ret));
  } else if (max_used_subpart_id >= 0 && max_used_subpart_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_subpart_id is invalid", K(ret), K(max_used_subpart_id), K(node->num_child_));
  } else {
    const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
    int64_t partition_num = node->num_child_;
    ObSubPartition subpartition;
    bool init_specified = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
      subpartition.reset();
      ObString partition_name;
      int64_t subpart_id = OB_INVALID_ID;
      bool current_spec = false;

      // 1. check partition name
      if (OB_ISNULL(element_node = node->children_[i])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret));
      } else if (OB_FAIL(resolve_partition_name(
                     element_node->children_[PARTITION_NAME_NODE], partition_name, subpartition))) {
        LOG_WARN("failed to resolve partition name", K(ret));
      } else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
                     stmt,
                     max_used_subpart_id,
                     partition_num,
                     i,
                     subpart_id,
                     current_spec))) {
        LOG_WARN("failed to resolve partition part id", K(ret));
      } else {
        // all partition should both specified part id or not
        if (0 == i) {
          init_specified = current_spec;
        } else if (init_specified != current_spec) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
        }
      }
      // add hash subpartition elements to table schema or partition
      if (OB_SUCC(ret)) {
        subpartition.set_part_id(part_id);
        subpartition.set_sub_part_id(subpart_id);
        subpartition.set_sub_part_idx(i);
        if (is_template) {
          if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
            LOG_WARN("failed to add partition", K(ret));
          }
        } else if (OB_FAIL(partition->add_partition(subpartition))) {
          LOG_WARN("failed to add partition", K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (is_template) {
        table_schema.get_sub_part_option().set_part_num(partition_num);
      } else {
        partition->set_sub_part_num(partition_num);
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_range_partition_elements(ObPartitionedStmt* stmt, ParseNode* node,
    ObTableSchema& table_schema, const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObIArray<ObRawExpr*>& range_value_exprs, int64_t max_used_part_id, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  ParseNode* element_node = NULL;
  ParseNode* expr_list_node = NULL;
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt));
  } else if (max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ObPartition partition;
    bool init_specified = false;
    // ignore alter_table with part_id
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
      partition.reset();
      ObString partition_name;
      int64_t part_id = OB_INVALID_ID;
      bool current_spec = false;
      if (OB_ISNULL(element_node = node->children_[i]) ||
          OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE]) ||
          OB_UNLIKELY(T_EXPR_LIST != expr_list_node->type_)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected node", K(ret), K(element_node), K(expr_list_node));
      } else if (part_func_exprs.count() != expr_list_node->num_child_) {
        ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
        LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
      } else if (OB_FAIL(
                     resolve_partition_name(element_node->children_[PARTITION_NAME_NODE], partition_name, partition))) {
        LOG_WARN("failed to resolve partition name", K(ret));
      } else if (OB_FAIL(resolve_range_partition_value_node(
                     *expr_list_node, partition_name, part_type, part_func_exprs, range_value_exprs, in_tablegroup))) {
        LOG_WARN("failed to resolve range partition value node", K(ret));
      } else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
                     stmt,
                     max_used_part_id,
                     partition_num,
                     i,
                     part_id,
                     current_spec))) {
        LOG_WARN("failed to resolve partition part id", K(ret));
      } else {
        if (0 == i) {
          init_specified = current_spec;
        } else if (current_spec != init_specified) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
        }
      }

      // add range partition elements to table schema
      if (OB_SUCC(ret)) {
        partition.set_part_id(part_id);
        if (OB_FAIL(table_schema.check_part_id(partition))) {
          LOG_WARN("failed to check part id", K(ret));
        } else if (OB_FAIL(table_schema.add_partition(partition))) {
          LOG_WARN("failed to add partition", K(ret));
        } else if (table_schema.is_sub_part_template() &&
                   OB_NOT_NULL(element_node->children_[ELEMENT_SUBPARTITION_NODE])) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("individual subpartition with sub part template", K(ret));
        } else if (!table_schema.is_sub_part_template()) {
          // resolve non template
          ObPartition* cur_partition = table_schema.get_part_array()[i];
          if (OB_ISNULL(cur_partition)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("get unexpected null", K(ret));
          } else if (OB_FAIL(resolve_subpartition_elements(stmt,
                         element_node->children_[ELEMENT_SUBPARTITION_NODE],
                         table_schema,
                         cur_partition,
                         false))) {
            LOG_WARN("failed to resolve subpartition elements", K(ret));
          }
        }
      }
    }
    if (OB_SUCC(ret)) {
      table_schema.get_part_option().set_part_num(partition_num);
    }
  }
  return ret;
}

int ObDDLResolver::resolve_range_subpartition_elements(ObPartitionedStmt* stmt, ParseNode* node,
    ObTableSchema& table_schema, ObPartition* partition, const ObPartitionFuncType part_type,
    const ObIArray<ObRawExpr*>& part_func_exprs, ObIArray<ObRawExpr*>& range_value_exprs, int64_t max_used_subpart_id,
    const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  ParseNode* element_node = NULL;
  ParseNode* expr_list_node = NULL;
  const bool is_template = table_schema.is_sub_part_template();
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt));
  } else if (!is_template && OB_ISNULL(partition)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("partition is null while not sub part template", K(ret));
  } else if (max_used_subpart_id >= 0 && max_used_subpart_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_subpart_id is invalid", K(ret), K(max_used_subpart_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ObSubPartition subpartition;
    bool init_specified = false;
    const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
    // ignore alter_table with part_id
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
      subpartition.reset();
      ObString partition_name;
      int64_t subpart_id = OB_INVALID_ID;
      bool current_spec = false;
      if (OB_ISNULL(element_node = node->children_[i]) ||
          OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE]) ||
          OB_UNLIKELY(T_EXPR_LIST != expr_list_node->type_)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected node", K(ret), K(element_node), K(expr_list_node));
      } else if (part_func_exprs.count() != expr_list_node->num_child_) {
        ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
        LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
      } else if (OB_FAIL(resolve_partition_name(
                     element_node->children_[PARTITION_NAME_NODE], partition_name, subpartition))) {
        LOG_WARN("failed to resolve partition name", K(ret));
      } else if (OB_FAIL(resolve_range_partition_value_node(
                     *expr_list_node, partition_name, part_type, part_func_exprs, range_value_exprs, in_tablegroup))) {
        LOG_WARN("failed to resolve range partition value node", K(ret));
      } else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
                     stmt,
                     max_used_subpart_id,
                     partition_num,
                     i,
                     subpart_id,
                     current_spec))) {
        LOG_WARN("failed to resolve partition part id", K(ret));
      } else {
        if (0 == i) {
          init_specified = current_spec;
        } else if (current_spec != init_specified) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
        }
      }

      // add range partition elements to table schema
      if (OB_SUCC(ret)) {
        subpartition.set_part_id(part_id);
        subpartition.set_sub_part_id(subpart_id);
        if (is_template) {
          if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
            LOG_WARN("failed to add partition", K(ret));
          }
        } else if (OB_FAIL(partition->add_partition(subpartition))) {
          LOG_WARN("failed to add partition", K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (is_template) {
        table_schema.get_sub_part_option().set_part_num(partition_num);
      } else {
        partition->set_sub_part_num(partition_num);
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_list_partition_elements(ObPartitionedStmt* stmt, ParseNode* node,
    ObTableSchema& table_schema, const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObDDLStmt::array_t& list_value_exprs, int64_t max_used_part_id, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  ParseNode* element_node = NULL;
  ParseNode* expr_list_node = NULL;
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(node), K(stmt));
  } else if (max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ObPartition partition;
    bool init_specified = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
      partition.reset();
      ObString partition_name;
      int64_t part_id = OB_INVALID_PARTITION_ID;
      bool current_spec = false;
      if (OB_ISNULL(element_node = node->children_[i]) ||
          OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpect node", K(ret), K(element_node), K(expr_list_node));
      } else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected node type", K(ret), K(expr_list_node->type_));
      } else if (OB_FAIL(
                     resolve_partition_name(element_node->children_[PARTITION_NAME_NODE], partition_name, partition))) {
        LOG_WARN("failed to resolve partition name", K(ret));
      } else if (OB_FAIL(resolve_list_partition_value_node(
                     *expr_list_node, partition_name, part_type, part_func_exprs, list_value_exprs, in_tablegroup))) {
        LOG_WARN("failed to resolve list partiton value node", K(ret));
      } else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
                     stmt,
                     max_used_part_id,
                     partition_num,
                     i,
                     part_id,
                     current_spec))) {
        LOG_WARN("failed to resolve partition part id", K(ret));
      } else {
        if (0 == i) {
          init_specified = current_spec;
        } else if (current_spec != init_specified) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
        }
      }

      // add list partition elements to table schema
      if (OB_SUCC(ret)) {
        partition.set_part_id(part_id);
        if (OB_FAIL(table_schema.check_part_id(partition))) {
          LOG_WARN("failed to check part id", K(ret));
        } else if (OB_FAIL(table_schema.add_partition(partition))) {
          LOG_WARN("failed to add partition", K(ret));
        } else if (table_schema.is_sub_part_template() &&
                   OB_NOT_NULL(element_node->children_[ELEMENT_SUBPARTITION_NODE])) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("individual subpartition with sub part template", K(ret));
        } else if (!table_schema.is_sub_part_template()) {
          // resolve non template
          ObPartition* cur_partition = table_schema.get_part_array()[i];
          if (OB_ISNULL(cur_partition)) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("get unexpected null", K(ret));
          } else if (OB_FAIL(resolve_subpartition_elements(stmt,
                         element_node->children_[ELEMENT_SUBPARTITION_NODE],
                         table_schema,
                         cur_partition,
                         false))) {
            LOG_WARN("failed to resolve subpartition elements", K(ret));
          }
        }
      }
    }
    if (OB_SUCC(ret)) {
      table_schema.get_part_option().set_part_num(partition_num);
    }
  }
  return ret;
}

int ObDDLResolver::resolve_list_subpartition_elements(ObPartitionedStmt* stmt, ParseNode* node,
    ObTableSchema& table_schema, ObPartition* partition, const ObPartitionFuncType part_type,
    const ObIArray<ObRawExpr*>& part_func_exprs, ObDDLStmt::array_t& list_value_exprs, int64_t max_used_subpart_id,
    const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  ParseNode* element_node = NULL;
  ParseNode* expr_list_node = NULL;
  const bool is_template = table_schema.is_sub_part_template();
  if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt_));
  } else if (max_used_subpart_id >= 0 && max_used_subpart_id < node->num_child_ - 1) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("max_used_subpart_id is invalid", K(ret), K(max_used_subpart_id), K(node->num_child_));
  } else {
    int64_t partition_num = node->num_child_;
    ObSubPartition subpartition;
    const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
    bool init_specified = false;
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
      subpartition.reset();
      ObString partition_name;
      int64_t subpart_id = OB_INVALID_ID;
      bool current_spec = false;
      if (OB_ISNULL(element_node = node->children_[i]) ||
          OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpect node", K(ret), K(element_node), K(expr_list_node));
      } else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected node type", K(ret), K(expr_list_node->type_));
      } else if (OB_FAIL(resolve_partition_name(
                     element_node->children_[PARTITION_NAME_NODE], partition_name, subpartition))) {
        LOG_WARN("failed to resolve partition name", K(ret));
      } else if (OB_FAIL(resolve_list_partition_value_node(
                     *expr_list_node, partition_name, part_type, part_func_exprs, list_value_exprs, in_tablegroup))) {
        LOG_WARN("failed to resolve list partiton value node", K(ret));
      } else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
                     stmt,
                     max_used_subpart_id,
                     partition_num,
                     i,
                     subpart_id,
                     current_spec))) {
        LOG_WARN("failed to resolve partition part id", K(ret));
      } else {
        if (0 == i) {
          init_specified = current_spec;
        } else if (current_spec != init_specified) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("Should speicify part id for all parts", K(ret));
          LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
        }
      }

      // add list partition elements to table schema
      if (OB_SUCC(ret)) {
        subpartition.set_part_id(part_id);
        subpartition.set_sub_part_id(subpart_id);
        if (is_template) {
          if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
            LOG_WARN("failed to add partition", K(ret));
          }
        } else if (OB_FAIL(partition->add_partition(subpartition))) {
          LOG_WARN("failed to add partition", K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (is_template) {
        table_schema.get_sub_part_option().set_part_num(partition_num);
      } else {
        partition->set_sub_part_num(partition_num);
      }
    }
  }
  return ret;
}

int ObDDLResolver::resolve_range_partition_value_node(ParseNode& expr_list_node, const ObString& partition_name,
    const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObIArray<ObRawExpr*>& range_value_exprs, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  for (int64_t i = 0; OB_SUCC(ret) && i < expr_list_node.num_child_; ++i) {
    if (OB_ISNULL(expr_list_node.children_[i])) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("get null node", K(ret));
    } else if (T_NULL == expr_list_node.children_[i]->type_) {
      ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
      LOG_WARN("null value is not allowed in less than", K(ret));
    } else if (T_MAXVALUE == expr_list_node.children_[i]->type_) {
      ObRawExpr* maxvalue_expr = NULL;
      ObConstRawExpr* c_expr = NULL;
      c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
      if (OB_ISNULL(c_expr)) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_WARN("failed to allocate memory", K(ret));
      } else {
        c_expr = new (c_expr) ObConstRawExpr();
        maxvalue_expr = c_expr;
        maxvalue_expr->set_data_type(common::ObMaxType);
        if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
          LOG_WARN("array push back fail", K(ret));
        }
      }
    } else if (T_EXPR_LIST != expr_list_node.children_[i]->type_) {
      ObRawExpr* part_value_expr = NULL;
      ObRawExpr* part_func_expr = NULL;
      if (OB_FAIL(part_func_exprs.at(i, part_func_expr))) {
        LOG_WARN("get part expr failed", K(i), "size", part_func_exprs.count(), K(ret));
      } else if (OB_ISNULL(part_func_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("part_func_expr is invalid", K(ret));
      } else if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(params_,
                     *(expr_list_node.children_[i]),
                     partition_name,
                     part_type,
                     *part_func_expr,
                     part_value_expr,
                     in_tablegroup))) {
        LOG_WARN("resolve partition expr failed", K(ret));
      } else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
        LOG_WARN("array push back fail", K(ret));
      }
    } else {
      ret = OB_ERR_PARSER_SYNTAX;
      LOG_WARN("syntax error, expect single expr while expr list got", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::resolve_list_partition_value_node(ParseNode& expr_list_node, const ObString& partition_name,
    const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
    ObDDLStmt::array_t& list_value_exprs, const bool& in_tablegroup)
{
  int ret = OB_SUCCESS;
  ObOpRawExpr* row_expr = NULL;
  if (OB_ISNULL(params_.expr_factory_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret));
  } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_OP_ROW, row_expr))) {
    LOG_WARN("failed to create raw expr", K(ret));
  } else if (OB_ISNULL(row_expr)) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_WARN("failed to allcoate memory", K(ret));
  } else if (T_DEFAULT == expr_list_node.type_) {
    ObRawExpr* maxvalue_expr = NULL;
    ObConstRawExpr* c_expr = NULL;
    c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
    if (OB_ISNULL(c_expr)) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_WARN("failed to allcoate memory", K(ret));
    } else {
      c_expr = new (c_expr) ObConstRawExpr();
      maxvalue_expr = c_expr;
      maxvalue_expr->set_data_type(common::ObMaxType);
      if (OB_FAIL(row_expr->add_param_expr(maxvalue_expr))) {
        LOG_WARN("failed add param expr", K(ret));
      }
    }
  } else {
    ObSEArray<ObRawExpr*, 16> part_value_exprs;
    bool is_all_expr_list = false;
    if (expr_list_node.num_child_ > 0) {
      is_all_expr_list = (expr_list_node.children_[0]->type_ == T_EXPR_LIST);
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < expr_list_node.num_child_; ++i) {
      part_value_exprs.reset();
      if ((is_all_expr_list && expr_list_node.children_[i]->type_ != T_EXPR_LIST) ||
          (!is_all_expr_list && expr_list_node.children_[i]->type_ == T_EXPR_LIST)) {
        ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
        LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
      } else if (OB_ISNULL(expr_list_node.children_[i])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("node is null", K(ret));
      } else if (OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(params_,
                     *(expr_list_node.children_[i]),
                     partition_name,
                     part_type,
                     part_func_exprs,
                     part_value_exprs,
                     in_tablegroup))) {
        LOG_WARN("resolve partition expr failed", K(ret));
      }
      for (int64_t j = 0; OB_SUCC(ret) && j < part_value_exprs.count(); ++j) {
        if (OB_FAIL(row_expr->add_param_expr(part_value_exprs.at(j)))) {
          LOG_WARN("failed add param expr", K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (part_func_exprs.count() > 1 && !is_all_expr_list) {
        if (row_expr->get_param_count() != part_func_exprs.count()) {
          ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
          LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
        }
      }
    }
  }
  if (OB_SUCC(ret)) {
    if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
      LOG_WARN("failed to push back expr", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::generate_default_hash_part(
    const int64_t partition_num, const int64_t max_used_part_id, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  table_schema.get_part_option().set_part_num(partition_num);
  char name_buf[common::OB_MAX_PARTITION_NAME_LENGTH];
  for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
    ObPartition partition;
    partition.set_part_id(max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + i : i);
    partition.set_part_idx(i);
    ObString part_name;
    MEMSET(name_buf, 0, common::OB_MAX_PARTITION_NAME_LENGTH);

    if (OB_FAIL(table_schema.gen_hash_part_name(partition.get_part_idx(),
            ObHashNameType::FIRST_PART,
            is_oracle_mode(),
            name_buf,
            common::OB_MAX_PARTITION_NAME_LENGTH,
            NULL))) {
      LOG_WARN("failed to gen hash part name", K(ret));
    } else if (FALSE_IT(part_name = ObString(strlen(name_buf), name_buf))) {
    } else if (OB_FAIL(partition.set_part_name(part_name))) {
      LOG_WARN("fail to set part name", K(ret));
    } else if (OB_FAIL(table_schema.check_part_name(partition))) {
      LOG_WARN("fail to check part name", K(ret));
    } else if (OB_FAIL(table_schema.add_partition(partition))) {
      LOG_WARN("fail to add partition", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::generate_default_hash_subpart(
    const int64_t partition_num, const int64_t max_used_subpart_id, ObTableSchema& table_schema, ObPartition* partition)
{
  int ret = OB_SUCCESS;
  char name_buf[common::OB_MAX_PARTITION_NAME_LENGTH];
  const bool is_template = table_schema.is_sub_part_template();
  if (!is_template && OB_ISNULL(partition)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("table is not subpart template by partition is null", K(ret));
  } else if (is_template) {
    table_schema.get_sub_part_option().set_part_num(partition_num);
  } else {
    partition->set_sub_part_num(partition_num);
  }
  if (OB_SUCC(ret)) {
    const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
    for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
      ObSubPartition subpartition;
      subpartition.set_part_id(part_id);
      subpartition.set_sub_part_id(max_used_subpart_id >= 0 ? max_used_subpart_id - partition_num + 1 + i : i);
      subpartition.set_sub_part_idx(i);
      ObString subpart_name;
      MEMSET(name_buf, 0, common::OB_MAX_PARTITION_NAME_LENGTH);
      if (is_template && OB_FAIL(table_schema.gen_hash_part_name(subpartition.get_sub_part_idx(),
                             ObHashNameType::TEMPLATE_SUB_PART,
                             is_oracle_mode(),
                             name_buf,
                             common::OB_MAX_PARTITION_NAME_LENGTH,
                             NULL))) {
        LOG_WARN("faield to gen hash part name", K(ret));
      } else if (!is_template && OB_FAIL(table_schema.gen_hash_part_name(subpartition.get_sub_part_idx(),
                                     ObHashNameType::INDIVIDUAL_SUB_PART,
                                     is_oracle_mode(),
                                     name_buf,
                                     common::OB_MAX_PARTITION_NAME_LENGTH,
                                     NULL,
                                     partition))) {
        LOG_WARN("faield to gen hash part name", K(ret));
      } else if (FALSE_IT(subpart_name = ObString(strlen(name_buf), name_buf))) {
      } else if (OB_FAIL(subpartition.set_part_name(subpart_name))) {
        LOG_WARN("fail to set part name", K(ret));
      } else if (is_template) {
        if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
          LOG_WARN("fail to add partition", K(ret));
        }
      } else if (OB_FAIL(partition->add_partition(subpartition))) {
        LOG_WARN("failed to add partition", K(ret));
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_and_set_partition_names(ObPartitionedStmt* stmt, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  if (OB_FAIL(check_and_set_partition_names(stmt, table_schema, false))) {
    LOG_WARN("failed to check and set partition names", K(ret));
  } else if (PARTITION_LEVEL_TWO == table_schema.get_part_level()) {
    if (table_schema.is_sub_part_template()) {
      if (OB_FAIL(check_and_set_partition_names(stmt, table_schema, true))) {
        LOG_WARN("failed to check and set partition names", K(ret));
      }
    } else if (OB_FAIL(check_and_set_individual_subpartition_names(stmt, table_schema))) {
      LOG_WARN("failed to check and set individual subpartition names", K(ret));
    }
  }
  return ret;
}

int ObDDLResolver::check_and_set_partition_names(ObPartitionedStmt* stmt, ObTableSchema& table_schema, bool is_subpart)
{
  int ret = OB_SUCCESS;
  hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>* partition_name_set = nullptr;
  void* buf = nullptr;
  int64_t partition_num = is_subpart ? table_schema.get_def_sub_part_num() : table_schema.get_first_part_num();
  ObBasePartition* partition = NULL;
  ObPartition** partition_array = table_schema.get_part_array();
  ObSubPartition** subpartition_array = table_schema.get_def_subpart_array();
  ObSEArray<int64_t, 128> empty_part_idx;
  if (is_subpart && OB_ISNULL(subpartition_array)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get null subpartition array", K(ret));
  } else if (!is_subpart && OB_ISNULL(partition_array)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get null partition array", K(ret));
  } else if (OB_ISNULL(buf = allocator_->alloc(sizeof(
                           hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>)))) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_WARN("fail to allocate memory", KR(ret));
  } else {
    partition_name_set = new (buf) hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>();
    if (OB_ISNULL(partition_name_set)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("partition name hash set is null", KR(ret));
    }
  }

  for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
    if (is_subpart) {
      partition = subpartition_array[i];
    } else {
      partition = partition_array[i];
    }
    if (OB_ISNULL(partition)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("get unexpected null", K(ret));
    } else if (partition->is_empty_partition_name()) {
      if (OB_FAIL(empty_part_idx.push_back(i))) {
        LOG_WARN("failed to push back part idx", K(ret));
      }
    } else {
      const ObString& partition_name = partition->get_part_name();
      ObPartitionNameHashWrapper partition_name_key(partition_name);
      if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
        ret = OB_ERR_SAME_NAME_PARTITION;
        LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION, partition_name.length(), partition_name.ptr());
      } else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
        LOG_WARN("add partition name to map failed", K(ret), K(ret));
      }
    }
  }

  if (OB_SUCC(ret) && !empty_part_idx.empty() &&
      (stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
          stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
    int64_t max_part_id = OB_MAX_PARTITION_NUM_MYSQL;
    ObString part_name_str;
    for (int64_t i = 0; OB_SUCC(ret) && i < empty_part_idx.count(); ++i) {
      const int64_t part_idx = empty_part_idx.at(i);
      if (is_subpart) {
        partition = subpartition_array[part_idx];
      } else {
        partition = partition_array[part_idx];
      }
      bool is_valid = false;
      while (OB_SUCC(ret) && !is_valid) {
        char part_name[OB_MAX_PARTITION_NAME_LENGTH];
        int64_t pos = 0;
        if (OB_FAIL(databuff_printf(part_name, OB_MAX_PARTITION_NAME_LENGTH, pos, "P%ld", max_part_id))) {
          LOG_WARN("failed to print databuff", K(ret), K(max_part_id));
        } else {
          part_name_str.assign(part_name, static_cast<int32_t>(pos));
          ObPartitionNameHashWrapper partition_name_key(part_name_str);
          if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
            // do nothing
          } else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
            LOG_WARN("add partition name to map failed", K(ret), K(ret));
          } else if (OB_FAIL(partition->set_part_name(part_name_str))) {
            LOG_WARN("failed to set part name", K(ret));
          } else {
            partition->set_is_empty_partition_name(false);
            is_valid = true;
          }
        }
        ++max_part_id;
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_and_set_individual_subpartition_names(ObPartitionedStmt* stmt, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>* partition_name_set = nullptr;
  void* buf = nullptr;
  int64_t partition_num = table_schema.get_first_part_num();
  ObPartition** partition_array = NULL;
  ObPartition* partition = NULL;
  ObSubPartition** subpartition_array = NULL;
  ObSubPartition* subpartition = NULL;
  ObSEArray<int64_t, 128> empty_part_idx;
  ObSEArray<int64_t, 128> empty_subpart_idx;
  if (OB_UNLIKELY(table_schema.is_sub_part_template())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected subpartition", K(ret));
  } else if (OB_ISNULL(partition_array = table_schema.get_part_array())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret));
  } else if (OB_ISNULL(buf = allocator_->alloc(sizeof(
                           hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>)))) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_WARN("fail to allocate memory", KR(ret));
  } else {
    partition_name_set = new (buf) hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>();
    if (OB_ISNULL(partition_name_set)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("partition name hash set is null", KR(ret));
    }
  }

  for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
    if (OB_ISNULL(partition = partition_array[i]) || OB_ISNULL(subpartition_array = partition->get_subpart_array())) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("get unexpected null", K(ret), K(partition), K(subpartition_array));
    }
    for (int64_t j = 0; OB_SUCC(ret) && j < partition->get_sub_part_num(); ++j) {
      if (OB_ISNULL(subpartition = subpartition_array[j])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret));
      } else if (subpartition->is_empty_partition_name()) {
        if (OB_FAIL(empty_part_idx.push_back(i))) {
          LOG_WARN("failed to push back part idx", K(ret));
        } else if (OB_FAIL(empty_subpart_idx.push_back(j))) {
          LOG_WARN("failed to push back subpart idx", K(ret));
        }
      } else {
        const ObString& partition_name = subpartition->get_part_name();
        ObPartitionNameHashWrapper partition_name_key(partition_name);
        if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
          ret = OB_ERR_SAME_NAME_SUBPARTITION;
          LOG_USER_ERROR(OB_ERR_SAME_NAME_SUBPARTITION, partition_name.length(), partition_name.ptr());
        } else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
          LOG_WARN("add partition name to map failed", K(ret), K(ret));
        }
      }
    }
  }

  if (!empty_part_idx.empty() &&
      (stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
          stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
    int64_t max_part_id = OB_MAX_PARTITION_NUM_MYSQL;
    ObString part_name_str;
    for (int64_t i = 0; OB_SUCC(ret) && i < empty_part_idx.count(); ++i) {
      int64_t part_idx = empty_part_idx.at(i);
      int64_t subpart_idx = empty_subpart_idx.at(i);
      subpartition = partition_array[part_idx]->get_subpart_array()[subpart_idx];
      bool is_valid = false;
      while (OB_SUCC(ret) && !is_valid) {
        char part_name[OB_MAX_PARTITION_NAME_LENGTH];
        int64_t pos = 0;
        if (OB_FAIL(databuff_printf(part_name, OB_MAX_PARTITION_NAME_LENGTH, pos, "P%ld", max_part_id))) {
          LOG_WARN("failed to print databuff", K(ret), K(max_part_id));
        } else {
          part_name_str.assign(part_name, static_cast<int32_t>(pos));
          ObPartitionNameHashWrapper partition_name_key(part_name_str);
          if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
            // do nothing
          } else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
            LOG_WARN("add partition name to map failed", K(ret), K(ret));
          } else if (OB_FAIL(subpartition->set_part_name(part_name_str))) {
            LOG_WARN("failed to set part name", K(ret));
          } else {
            subpartition->set_is_empty_partition_name(false);
            is_valid = true;
          }
        }
        ++max_part_id;
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_individual_subpartition_define(ObPartitionedStmt* stmt, ObTableSchema& table_schema)
{
  int ret = OB_SUCCESS;
  int64_t partition_num = table_schema.get_first_part_num();
  ObPartition** partition_array = NULL;
  ObPartition* partition = NULL;
  bool need_check_value = table_schema.is_range_subpart() || table_schema.is_list_subpart();
  if (OB_ISNULL(stmt) || OB_ISNULL(partition_array = table_schema.get_part_array())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(stmt), K(partition_array));
  } else if (OB_UNLIKELY(table_schema.is_sub_part_template())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected subpartition", K(ret), K(table_schema.is_sub_part_template()));
  } else if (need_check_value && partition_num != stmt->get_individual_subpart_values_exprs().count()) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected subpartition value exprs",
        K(ret),
        K(partition_num),
        K(stmt->get_individual_subpart_values_exprs()));
  } else if (partition_num <= 1) {
    // do nothing
  } else if (OB_ISNULL(partition = partition_array[0])) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(partition));
  } else {
    const int64_t first_subpart_number = partition->get_sub_part_num();
    const ObIArray<ObRawExpr*>* first_subpart_value_exprs = NULL;
    if (need_check_value) {
      first_subpart_value_exprs = &(stmt->get_individual_subpart_values_exprs().at(0));
    }
    for (int64_t i = 1; OB_SUCC(ret) && i < partition_num; ++i) {
      if (OB_ISNULL(partition = partition_array[i])) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(partition));
      } else if (first_subpart_number != partition->get_sub_part_num()) {
        ret = OB_NOT_SUPPORTED;
        LOG_USER_ERROR(OB_NOT_SUPPORTED, "individual subpartition with different define");
      } else if (need_check_value) {
        const ObIArray<ObRawExpr*>& cur_value_exprs = stmt->get_individual_subpart_values_exprs().at(i);
        const ObRawExpr* l_expr = NULL;
        const ObRawExpr* r_expr = NULL;
        for (int64_t j = 0; OB_SUCC(ret) && j < first_subpart_value_exprs->count(); ++j) {
          if (OB_ISNULL(l_expr = first_subpart_value_exprs->at(j)) || OB_ISNULL(r_expr = cur_value_exprs.at(j))) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("get unexpected null", K(ret), K(l_expr), K(r_expr));
          } else if (!l_expr->same_as(*r_expr)) {
            ret = OB_NOT_SUPPORTED;
            LOG_USER_ERROR(OB_NOT_SUPPORTED, "individual subpartition with different define");
          }
        }
      }
    }
  }
  return ret;
}

int ObDDLResolver::check_max_used_subpart_id_valid(
    const share::schema::ObTableSchema& table_schema, const ObPartition& partition, int64_t& max_used_subpart_id)
{
  int ret = OB_SUCCESS;
  int64_t current_max_subpart_id = -1;
  const int64_t subpart_num = partition.get_sub_part_num();
  if (table_schema.is_range_subpart() || table_schema.is_list_subpart()) {
    ObSubPartition** subpart_array = partition.get_subpart_array();
    const int64_t subpart_idx = subpart_num - 1;
    if (subpart_idx < 0) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("Invalid part idx", K(ret));
    } else if (OB_ISNULL(subpart_array)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("Empty partition", K(ret));
    } else if (OB_ISNULL(subpart_array[subpart_idx])) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("NULL ptr", K(ret));
    } else if (subpart_array[subpart_idx]->get_sub_part_id() < 0) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("Invalid part id", K(ret), K(subpart_idx), K(subpart_array[subpart_idx]->get_sub_part_id()));
    } else {
      current_max_subpart_id = subpart_array[subpart_idx]->get_sub_part_id();
    }
  } else {
    current_max_subpart_id = subpart_num - 1;
  }
  if (OB_SUCC(ret)) {
    if (max_used_subpart_id < 0) {
      max_used_subpart_id = current_max_subpart_id;
    } else if (PARTITION_LEVEL_ZERO == table_schema.get_part_level() ||
               PARTITION_LEVEL_ONE == table_schema.get_part_level()) {
      ret = OB_NOT_SUPPORTED;
      SQL_RESV_LOG(WARN, "non subpart table with max_used_sub_part_id not support", K(ret), K(current_max_subpart_id));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "non subpart table with max_used_sub_part_id");
    } else if (max_used_subpart_id < current_max_subpart_id) {
      ret = OB_INVALID_ARGUMENT;
      SQL_RESV_LOG(WARN, "invalid max_used_subpart_id", K(ret), K(max_used_subpart_id), K(current_max_subpart_id));
      LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max_used_subpart_id");
    } else {
      // use max_used_part_id_
    }
  }
  return ret;
}

}  // namespace sql
}  // namespace oceanbase
